"""
Data Seeder Service for populating the database with test data.
Can be controlled via API for admin-initiated seeding.
"""

import random
from decimal import Decimal
from datetime import datetime, timedelta
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.models import (
    User, Wallet, SportEvent, SpreadBet, EventComment,
    SportType, EventStatus, SpreadBetStatus, TeamSide
)
from app.schemas.admin import SeedRequest, SeedResponse
from app.services.audit_service import log_data_seed
from app.utils.security import get_password_hash


# Sample data for generating random content
FIRST_NAMES = [
    "James", "Emma", "Liam", "Olivia", "Noah", "Ava", "Oliver", "Sophia",
    "Elijah", "Isabella", "Lucas", "Mia", "Mason", "Charlotte", "Ethan",
    "Amelia", "Alexander", "Harper", "Henry", "Evelyn", "Sebastian", "Luna",
    "Jack", "Camila", "Aiden", "Gianna", "Owen", "Abigail", "Samuel", "Ella",
]

LAST_NAMES = [
    "Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller",
    "Davis", "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez",
    "Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin",
]

NFL_TEAMS = [
    ("Kansas City Chiefs", "Arrowhead Stadium"),
    ("San Francisco 49ers", "Levi's Stadium"),
    ("Philadelphia Eagles", "Lincoln Financial Field"),
    ("Dallas Cowboys", "AT&T Stadium"),
    ("Buffalo Bills", "Highmark Stadium"),
    ("Miami Dolphins", "Hard Rock Stadium"),
    ("Detroit Lions", "Ford Field"),
    ("Green Bay Packers", "Lambeau Field"),
    ("Baltimore Ravens", "M&T Bank Stadium"),
    ("Cincinnati Bengals", "Paycor Stadium"),
]

NBA_TEAMS = [
    ("Boston Celtics", "TD Garden"),
    ("Denver Nuggets", "Ball Arena"),
    ("Milwaukee Bucks", "Fiserv Forum"),
    ("Los Angeles Lakers", "Crypto.com Arena"),
    ("Phoenix Suns", "Footprint Center"),
    ("Golden State Warriors", "Chase Center"),
    ("Miami Heat", "Kaseya Center"),
    ("Cleveland Cavaliers", "Rocket Mortgage FieldHouse"),
]

EVENT_COMMENTS = [
    "This is going to be a great game!",
    "Home team looking strong this season",
    "I'm betting on the underdog here",
    "What do you all think about the spread?",
    "Last time these teams played it was close",
    "The odds seem off to me",
    "Sharp money coming in on the home side",
    "Value play on the underdog here",
    "Home field advantage is huge here",
    "Rivalry game, throw out the records!",
]


class SeederService:
    """Service for seeding the database with test data."""

    @staticmethod
    async def seed(
        db: AsyncSession,
        admin: User,
        request: SeedRequest,
        ip_address: Optional[str] = None,
    ) -> SeedResponse:
        """
        Seed the database with test data.
        """
        created_counts = {
            "users": 0,
            "wallets": 0,
            "events": 0,
            "bets": 0,
            "comments": 0,
        }
        test_admin_info = None

        # Create test admin if requested and doesn't exist
        if request.create_admin:
            existing_admin = await db.execute(
                select(User).where(User.username == "testadmin")
            )
            if not existing_admin.scalar_one_or_none():
                test_admin = User(
                    email="testadmin@example.com",
                    username="testadmin",
                    password_hash=get_password_hash("admin123"),
                    display_name="Test Administrator",
                    is_admin=True,
                )
                db.add(test_admin)
                await db.flush()

                admin_wallet = Wallet(
                    user_id=test_admin.id,
                    balance=Decimal("10000.00"),
                    escrow=Decimal("0.00"),
                )
                db.add(admin_wallet)
                created_counts["users"] += 1
                created_counts["wallets"] += 1
                test_admin_info = {
                    "username": "testadmin",
                    "email": "testadmin@example.com",
                    "password": "admin123",
                }

        # Create regular test users
        users = []
        for i in range(request.num_users):
            first = random.choice(FIRST_NAMES)
            last = random.choice(LAST_NAMES)
            suffix = random.randint(100, 9999)
            username = f"{first.lower()}{last.lower()}{suffix}"
            email = f"{username}@example.com"

            # Check if user already exists
            existing = await db.execute(
                select(User).where(User.username == username)
            )
            if existing.scalar_one_or_none():
                continue

            user = User(
                email=email,
                username=username,
                password_hash=get_password_hash("password123"),
                display_name=f"{first} {last}",
            )
            db.add(user)
            await db.flush()

            wallet = Wallet(
                user_id=user.id,
                balance=request.starting_balance,
                escrow=Decimal("0.00"),
            )
            db.add(wallet)

            users.append(user)
            created_counts["users"] += 1
            created_counts["wallets"] += 1

        # Create sport events
        events = []
        all_teams = [(t, v, SportType.FOOTBALL, "NFL") for t, v in NFL_TEAMS] + \
                   [(t, v, SportType.BASKETBALL, "NBA") for t, v in NBA_TEAMS]

        for i in range(request.num_events):
            # Pick two different teams from the same sport
            team_pool = random.choice([NFL_TEAMS, NBA_TEAMS])
            sport = SportType.FOOTBALL if team_pool == NFL_TEAMS else SportType.BASKETBALL
            league = "NFL" if sport == SportType.FOOTBALL else "NBA"

            home_team, venue = random.choice(team_pool)
            away_team, _ = random.choice([t for t in team_pool if t[0] != home_team])

            # Random game time in the next 7 days
            game_time = datetime.utcnow() + timedelta(
                days=random.randint(1, 7),
                hours=random.randint(0, 23),
            )

            # Random spread
            spread = round(random.uniform(-10, 10) * 2) / 2  # Half-point spread

            event = SportEvent(
                sport=sport,
                home_team=home_team,
                away_team=away_team,
                official_spread=spread,
                game_time=game_time,
                venue=venue,
                league=league,
                min_spread=-15.0,
                max_spread=15.0,
                min_bet_amount=Decimal("10.00"),
                max_bet_amount=Decimal("1000.00"),
                status=EventStatus.UPCOMING,
                created_by=admin.id,
            )
            db.add(event)
            await db.flush()
            events.append(event)
            created_counts["events"] += 1

        # Create bets on events
        if users and events:
            for event in events:
                num_bets = random.randint(1, request.num_bets_per_event * 2)
                for _ in range(num_bets):
                    user = random.choice(users)

                    # Random spread near official
                    spread_offset = random.choice([-2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2])
                    spread = event.official_spread + spread_offset
                    spread = max(event.min_spread, min(event.max_spread, spread))
                    # Ensure half-point
                    spread = round(spread * 2) / 2
                    if spread % 1 == 0:
                        spread += 0.5

                    stake = Decimal(str(random.randint(25, 200)))
                    team = random.choice([TeamSide.HOME, TeamSide.AWAY])

                    bet = SpreadBet(
                        event_id=event.id,
                        spread=spread,
                        team=team,
                        creator_id=user.id,
                        stake_amount=stake,
                        house_commission_percent=Decimal("10.00"),
                        status=SpreadBetStatus.OPEN,
                    )
                    db.add(bet)
                    created_counts["bets"] += 1

                # Add some comments
                for _ in range(random.randint(0, 3)):
                    user = random.choice(users)
                    comment = EventComment(
                        event_id=event.id,
                        user_id=user.id,
                        content=random.choice(EVENT_COMMENTS),
                    )
                    db.add(comment)
                    created_counts["comments"] += 1

        # Log the seed operation
        await log_data_seed(
            db=db,
            admin=admin,
            created_counts=created_counts,
            ip_address=ip_address,
        )

        await db.commit()

        return SeedResponse(
            success=True,
            message="Database seeded successfully",
            created_counts=created_counts,
            test_admin=test_admin_info,
        )
