#!/usr/bin/env python3
"""
Event Management Script
Manages sport events including:
- Creating new upcoming events
- Updating events to LIVE status
- Simulating live score updates
- Completing events and settling bets

Usage:
    python manage_events.py [--create N] [--update] [--settle] [--continuous] [--delay SECONDS]
"""

import asyncio
import argparse
import random
from decimal import Decimal
from datetime import datetime, timedelta
from sqlalchemy import select, and_
from sqlalchemy.orm import selectinload

from app.database import async_session, init_db
from app.models import (
    User, Wallet, SportEvent, SpreadBet, Transaction,
    SportType, EventStatus, SpreadBetStatus, TeamSide,
    TransactionType, TransactionStatus
)

# Team data by sport
TEAMS = {
    SportType.FOOTBALL: {
        "NFL": [
            ("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"),
            ("Baltimore Ravens", "M&T Bank Stadium"),
            ("Detroit Lions", "Ford Field"),
            ("Green Bay Packers", "Lambeau Field"),
            ("Seattle Seahawks", "Lumen Field"),
            ("New York Giants", "MetLife Stadium"),
            ("Los Angeles Rams", "SoFi Stadium"),
            ("Cincinnati Bengals", "Paycor Stadium"),
            ("Jacksonville Jaguars", "TIAA Bank Field"),
            ("Minnesota Vikings", "U.S. Bank Stadium"),
            ("New Orleans Saints", "Caesars Superdome"),
        ],
        "NCAA": [
            ("Alabama Crimson Tide", "Bryant-Denny Stadium"),
            ("Georgia Bulldogs", "Sanford Stadium"),
            ("Ohio State Buckeyes", "Ohio Stadium"),
            ("Michigan Wolverines", "Michigan Stadium"),
            ("Texas Longhorns", "Darrell K Royal Stadium"),
            ("USC Trojans", "Los Angeles Memorial Coliseum"),
            ("Clemson Tigers", "Memorial Stadium"),
            ("Penn State Nittany Lions", "Beaver Stadium"),
            ("Oregon Ducks", "Autzen Stadium"),
            ("Florida State Seminoles", "Doak Campbell Stadium"),
        ]
    },
    SportType.BASKETBALL: {
        "NBA": [
            ("Los Angeles Lakers", "Crypto.com Arena"),
            ("Boston Celtics", "TD Garden"),
            ("Golden State Warriors", "Chase Center"),
            ("Milwaukee Bucks", "Fiserv Forum"),
            ("Phoenix Suns", "Footprint Center"),
            ("Denver Nuggets", "Ball Arena"),
            ("Miami Heat", "Kaseya Center"),
            ("Philadelphia 76ers", "Wells Fargo Center"),
            ("Brooklyn Nets", "Barclays Center"),
            ("Dallas Mavericks", "American Airlines Center"),
            ("New York Knicks", "Madison Square Garden"),
            ("Cleveland Cavaliers", "Rocket Mortgage FieldHouse"),
        ],
        "NCAA": [
            ("Duke Blue Devils", "Cameron Indoor Stadium"),
            ("Kentucky Wildcats", "Rupp Arena"),
            ("Kansas Jayhawks", "Allen Fieldhouse"),
            ("North Carolina Tar Heels", "Dean E. Smith Center"),
            ("UCLA Bruins", "Pauley Pavilion"),
            ("Gonzaga Bulldogs", "McCarthey Athletic Center"),
            ("Villanova Wildcats", "Finneran Pavilion"),
            ("Arizona Wildcats", "McKale Center"),
        ]
    },
    SportType.BASEBALL: {
        "MLB": [
            ("New York Yankees", "Yankee Stadium"),
            ("Los Angeles Dodgers", "Dodger Stadium"),
            ("Boston Red Sox", "Fenway Park"),
            ("Chicago Cubs", "Wrigley Field"),
            ("Atlanta Braves", "Truist Park"),
            ("Houston Astros", "Minute Maid Park"),
            ("San Diego Padres", "Petco Park"),
            ("Philadelphia Phillies", "Citizens Bank Park"),
            ("Texas Rangers", "Globe Life Field"),
            ("San Francisco Giants", "Oracle Park"),
        ]
    },
    SportType.HOCKEY: {
        "NHL": [
            ("Vegas Golden Knights", "T-Mobile Arena"),
            ("Florida Panthers", "Amerant Bank Arena"),
            ("Edmonton Oilers", "Rogers Place"),
            ("Dallas Stars", "American Airlines Center"),
            ("Colorado Avalanche", "Ball Arena"),
            ("New York Rangers", "Madison Square Garden"),
            ("Boston Bruins", "TD Garden"),
            ("Carolina Hurricanes", "PNC Arena"),
            ("Toronto Maple Leafs", "Scotiabank Arena"),
            ("Tampa Bay Lightning", "Amalie Arena"),
        ]
    },
    SportType.SOCCER: {
        "EPL": [
            ("Manchester City", "Etihad Stadium"),
            ("Arsenal", "Emirates Stadium"),
            ("Liverpool", "Anfield"),
            ("Manchester United", "Old Trafford"),
            ("Chelsea", "Stamford Bridge"),
            ("Tottenham Hotspur", "Tottenham Hotspur Stadium"),
            ("Newcastle United", "St. James' Park"),
            ("Brighton", "American Express Stadium"),
        ],
        "MLS": [
            ("Inter Miami", "Chase Stadium"),
            ("LA Galaxy", "Dignity Health Sports Park"),
            ("LAFC", "BMO Stadium"),
            ("Atlanta United", "Mercedes-Benz Stadium"),
            ("Seattle Sounders", "Lumen Field"),
            ("New York Red Bulls", "Red Bull Arena"),
        ]
    }
}


def get_random_matchup(sport: SportType) -> tuple:
    """Get a random matchup for a sport."""
    leagues = TEAMS.get(sport, {})
    if not leagues:
        return None

    league = random.choice(list(leagues.keys()))
    teams = leagues[league]

    # Pick two different teams
    home_team, home_venue = random.choice(teams)
    away_team, _ = random.choice([t for t in teams if t[0] != home_team])

    return {
        "sport": sport,
        "league": league,
        "home_team": home_team,
        "away_team": away_team,
        "venue": home_venue
    }


def generate_spread(sport: SportType) -> float:
    """Generate a realistic spread for a sport."""
    if sport == SportType.FOOTBALL:
        # NFL/NCAA spreads typically -14 to +14
        spread = round(random.uniform(-10, 10) * 2) / 2
    elif sport == SportType.BASKETBALL:
        # NBA spreads can be larger
        spread = round(random.uniform(-12, 12) * 2) / 2
    elif sport == SportType.BASEBALL:
        # Baseball run lines are typically 1.5
        spread = random.choice([-1.5, 1.5, -2.5, 2.5])
    elif sport == SportType.HOCKEY:
        # Hockey puck lines are typically 1.5
        spread = random.choice([-1.5, 1.5, -2.5, 2.5])
    elif sport == SportType.SOCCER:
        # Soccer spreads are typically small
        spread = random.choice([-0.5, 0.5, -1, 1, -1.5, 1.5])
    else:
        spread = round(random.uniform(-7, 7) * 2) / 2

    return spread


async def create_new_events(db, admin_user_id: int, count: int = 5) -> list[SportEvent]:
    """Create new upcoming events."""
    events = []

    for _ in range(count):
        sport = random.choice(list(SportType))
        matchup = get_random_matchup(sport)

        if not matchup:
            continue

        # Random game time in the next 1-7 days
        hours_ahead = random.randint(1, 168)  # 1 hour to 7 days
        game_time = datetime.utcnow() + timedelta(hours=hours_ahead)

        spread = generate_spread(sport)

        event = SportEvent(
            sport=matchup["sport"],
            home_team=matchup["home_team"],
            away_team=matchup["away_team"],
            official_spread=spread,
            game_time=game_time,
            venue=matchup["venue"],
            league=matchup["league"],
            min_spread=spread - 5,
            max_spread=spread + 5,
            min_bet_amount=10.0,
            max_bet_amount=1000.0,
            status=EventStatus.UPCOMING,
            created_by=admin_user_id
        )
        db.add(event)
        events.append(event)

    await db.commit()

    for event in events:
        print(f"  [NEW] {event.home_team} vs {event.away_team} ({event.league}) - {event.game_time.strftime('%m/%d %H:%M')}")

    return events


async def update_events_to_live(db) -> list[SportEvent]:
    """Update events that should be live (game time has passed)."""
    # Find upcoming events where game time has passed
    result = await db.execute(
        select(SportEvent).where(
            and_(
                SportEvent.status == EventStatus.UPCOMING,
                SportEvent.game_time <= datetime.utcnow()
            )
        )
    )
    events = result.scalars().all()

    for event in events:
        event.status = EventStatus.LIVE
        event.final_score_home = 0
        event.final_score_away = 0
        print(f"  [LIVE] {event.home_team} vs {event.away_team} is now LIVE!")

    await db.commit()
    return list(events)


async def update_live_scores(db) -> list[SportEvent]:
    """Update scores for live events."""
    result = await db.execute(
        select(SportEvent).where(SportEvent.status == EventStatus.LIVE)
    )
    events = result.scalars().all()

    for event in events:
        # Randomly add points based on sport
        if event.sport == SportType.FOOTBALL:
            # Football scoring: 3 or 7 points typically
            if random.random() < 0.3:
                scorer = random.choice(['home', 'away'])
                points = random.choice([3, 7, 6, 2])
                if scorer == 'home':
                    event.final_score_home = (event.final_score_home or 0) + points
                else:
                    event.final_score_away = (event.final_score_away or 0) + points
                print(f"  [SCORE] {event.home_team} {event.final_score_home} - {event.final_score_away} {event.away_team}")

        elif event.sport == SportType.BASKETBALL:
            # Basketball: 2 or 3 points frequently
            if random.random() < 0.5:
                scorer = random.choice(['home', 'away'])
                points = random.choice([2, 2, 2, 3, 1])
                if scorer == 'home':
                    event.final_score_home = (event.final_score_home or 0) + points
                else:
                    event.final_score_away = (event.final_score_away or 0) + points
                print(f"  [SCORE] {event.home_team} {event.final_score_home} - {event.final_score_away} {event.away_team}")

        elif event.sport in [SportType.BASEBALL, SportType.HOCKEY, SportType.SOCCER]:
            # Low scoring sports
            if random.random() < 0.15:
                scorer = random.choice(['home', 'away'])
                if scorer == 'home':
                    event.final_score_home = (event.final_score_home or 0) + 1
                else:
                    event.final_score_away = (event.final_score_away or 0) + 1
                print(f"  [SCORE] {event.home_team} {event.final_score_home} - {event.final_score_away} {event.away_team}")

    await db.commit()
    return list(events)


async def complete_events(db) -> list[SportEvent]:
    """Complete live events that have been running long enough."""
    result = await db.execute(
        select(SportEvent).where(SportEvent.status == EventStatus.LIVE)
    )
    events = result.scalars().all()

    completed = []
    for event in events:
        # Calculate "game duration" based on when it went live (using updated_at as proxy)
        # Complete events after ~10 iterations (simulated game time)
        game_duration = (datetime.utcnow() - event.updated_at).total_seconds()

        # 20% chance to complete if scores are reasonable
        home_score = event.final_score_home or 0
        away_score = event.final_score_away or 0

        should_complete = False
        if event.sport == SportType.FOOTBALL and (home_score + away_score) >= 20:
            should_complete = random.random() < 0.3
        elif event.sport == SportType.BASKETBALL and (home_score + away_score) >= 150:
            should_complete = random.random() < 0.3
        elif event.sport in [SportType.BASEBALL, SportType.HOCKEY] and (home_score + away_score) >= 5:
            should_complete = random.random() < 0.3
        elif event.sport == SportType.SOCCER and (home_score + away_score) >= 2:
            should_complete = random.random() < 0.3

        if should_complete:
            event.status = EventStatus.COMPLETED
            completed.append(event)
            print(f"  [FINAL] {event.home_team} {home_score} - {away_score} {event.away_team}")

    await db.commit()
    return completed


async def settle_bets(db, completed_events: list[SportEvent]) -> int:
    """Settle bets for completed events."""
    settled_count = 0

    for event in completed_events:
        # Get all matched bets for this event
        result = await db.execute(
            select(SpreadBet)
            .options(selectinload(SpreadBet.creator), selectinload(SpreadBet.taker))
            .where(
                and_(
                    SpreadBet.event_id == event.id,
                    SpreadBet.status == SpreadBetStatus.MATCHED
                )
            )
        )
        bets = result.scalars().all()

        for bet in bets:
            # Calculate spread result
            home_score = event.final_score_home or 0
            away_score = event.final_score_away or 0
            actual_spread = home_score - away_score  # Positive = home won by X

            # Creator's pick
            if bet.team == TeamSide.HOME:
                # Creator bet on home team with the spread
                # Home team needs to "cover" - actual margin > bet spread
                creator_wins = actual_spread > bet.spread
            else:
                # Creator bet on away team
                # Away team needs to cover - actual margin < bet spread (inverted)
                creator_wins = actual_spread < -bet.spread

            # Get wallets
            creator_wallet_result = await db.execute(
                select(Wallet).where(Wallet.user_id == bet.creator_id)
            )
            creator_wallet = creator_wallet_result.scalar_one_or_none()

            taker_wallet_result = await db.execute(
                select(Wallet).where(Wallet.user_id == bet.taker_id)
            )
            taker_wallet = taker_wallet_result.scalar_one_or_none()

            if not creator_wallet or not taker_wallet:
                continue

            # Calculate payout (total pot minus commission)
            total_pot = bet.stake_amount * 2
            commission = total_pot * (bet.house_commission_percent / 100)
            payout = total_pot - commission

            winner = bet.creator if creator_wins else bet.taker
            winner_wallet = creator_wallet if creator_wins else taker_wallet
            loser_wallet = taker_wallet if creator_wins else creator_wallet

            # Release escrow and pay winner
            creator_wallet.escrow -= bet.stake_amount
            taker_wallet.escrow -= bet.stake_amount
            winner_wallet.balance += payout

            # Create payout transaction
            payout_tx = Transaction(
                user_id=winner.id,
                wallet_id=winner_wallet.id,
                type=TransactionType.BET_WON,
                amount=payout,
                balance_after=winner_wallet.balance,
                reference_id=bet.id,
                description=f"Won spread bet #{bet.id}",
                status=TransactionStatus.COMPLETED
            )
            db.add(payout_tx)

            # Update bet
            bet.status = SpreadBetStatus.COMPLETED
            bet.winner_id = winner.id
            bet.payout_amount = payout
            bet.completed_at = datetime.utcnow()

            settled_count += 1
            print(f"  [SETTLED] Bet #{bet.id}: {winner.username} wins ${payout:.2f}")

    await db.commit()
    return settled_count


async def run_event_management(
    create_count: int = 0,
    do_update: bool = False,
    do_settle: bool = False,
    continuous: bool = False,
    delay: float = 5.0
):
    """Run the event management script."""
    print("=" * 60)
    print("H2H Event Manager")
    print("=" * 60)

    await init_db()

    iteration = 0
    while True:
        iteration += 1
        print(f"\n--- Iteration {iteration} ---")

        async with async_session() as db:
            # Get or create admin user
            admin_result = await db.execute(
                select(User).where(User.is_admin == True)
            )
            admin = admin_result.scalar_one_or_none()

            if not admin:
                # Use first user as admin
                user_result = await db.execute(select(User).limit(1))
                admin = user_result.scalar_one_or_none()

            if not admin:
                print("  No users found. Run seed_data.py first.")
                if not continuous:
                    break
                await asyncio.sleep(delay)
                continue

            # Create new events
            if create_count > 0 or continuous:
                events_to_create = create_count if create_count > 0 else random.randint(1, 3)
                if continuous and random.random() < 0.3:  # 30% chance in continuous mode
                    print(f"\n  Creating {events_to_create} new events...")
                    await create_new_events(db, admin.id, events_to_create)
                elif create_count > 0:
                    print(f"\n  Creating {events_to_create} new events...")
                    await create_new_events(db, admin.id, events_to_create)

            # Update events
            if do_update or continuous:
                print("\n  Checking for events to update...")

                # Move upcoming to live
                await update_events_to_live(db)

                # Update live scores
                await update_live_scores(db)

                # Complete events
                completed = await complete_events(db)

                # Settle bets for completed events
                if (do_settle or continuous) and completed:
                    print(f"\n  Settling bets for {len(completed)} completed events...")
                    settled = await settle_bets(db, completed)
                    print(f"  Settled {settled} bets")

        if not continuous:
            break

        await asyncio.sleep(delay)

    print("\n" + "=" * 60)
    print("Event management complete!")
    print("=" * 60)


def main():
    parser = argparse.ArgumentParser(description="Manage H2H sport events")
    parser.add_argument(
        "--create", "-c",
        type=int,
        default=0,
        help="Number of new events to create (default: 0)"
    )
    parser.add_argument(
        "--update", "-u",
        action="store_true",
        help="Update event statuses and scores"
    )
    parser.add_argument(
        "--settle", "-s",
        action="store_true",
        help="Settle bets for completed events"
    )
    parser.add_argument(
        "--continuous",
        action="store_true",
        help="Run continuously until interrupted"
    )
    parser.add_argument(
        "--delay", "-d",
        type=float,
        default=5.0,
        help="Delay between iterations in seconds (default: 5.0)"
    )

    args = parser.parse_args()

    # If no specific action, just create events
    if not args.create and not args.update and not args.settle and not args.continuous:
        args.create = 5  # Default: create 5 events

    try:
        asyncio.run(run_event_management(
            create_count=args.create,
            do_update=args.update,
            do_settle=args.settle,
            continuous=args.continuous,
            delay=args.delay
        ))
    except KeyboardInterrupt:
        print("\n\nEvent management stopped by user.")


if __name__ == "__main__":
    main()
