"""
Time Skip System

Handles time skip purchases and simulation of game events during skipped periods.
"""

from datetime import datetime, timedelta
from typing import Dict, Any, List
import logging
from database import get_database_connection
from .validation import rate_limit

# Time skip tier configurations
SKIP_TIERS = {
    '1hour': {'duration': timedelta(hours=1), 'diamonds': 5},
    '1day': {'duration': timedelta(days=1), 'diamonds': 25},
    '1week': {'duration': timedelta(weeks=1), 'diamonds': 100},
    'next_event': {'duration': None, 'diamonds': 50}  # Variable duration
}


@rate_limit(max_calls=5, time_window=60)
def purchase_time_skip(player_id: int, skip_type: str) -> Dict[str, Any]:
    """
    Handle time skip purchase and simulation.

    Rate limited to 5 purchases per minute to prevent abuse.

    Args:
        player_id: The player's ID
        skip_type: Type of skip ('1hour', '1day', '1week', 'next_event')

    Returns:
        dict with 'success', 'message', and 'summary' keys
    """
    conn = None
    cursor = None

    try:
        # Validate skip type
        if skip_type not in SKIP_TIERS:
            return {
                'success': False,
                'message': f'Invalid skip type: {skip_type}'
            }

        tier = SKIP_TIERS[skip_type]
        diamond_cost = tier['diamonds']

        # Get database connection
        conn = get_database_connection()
        cursor = conn.cursor(dictionary=True)

        # Get player current state
        cursor.execute(
            """SELECT diamonds, date, hourOfDay, minuteOfHour,
                      energy, health, happiness, age, dead
               FROM players WHERE id = %s""",
            (player_id,)
        )
        player = cursor.fetchone()

        if not player:
            return {'success': False, 'message': 'Player not found'}

        if player['dead']:
            return {'success': False, 'message': 'Cannot skip time after death'}

        # Check diamond balance
        if player['diamonds'] < diamond_cost:
            return {
                'success': False,
                'message': f'Not enough diamonds. Need {diamond_cost}, have {player["diamonds"]}'
            }

        # Calculate skip duration
        time_before = player['date']
        if isinstance(time_before, str):
            time_before = datetime.fromisoformat(time_before)

        if skip_type == 'next_event':
            # Skip to next major event (simplified - skip 1 day for now)
            # TODO: Actually check scheduled events
            time_after = time_before + timedelta(days=1)
        else:
            time_after = time_before + tier['duration']

        # Simulate events during skipped period
        events_summary = simulate_time_period(player_id, time_before, time_after, cursor)

        # Update player time and stats with atomic diamond deduction (concurrent protection)
        cursor.execute(
            """UPDATE players
               SET diamonds = diamonds - %s, date = %s,
                   energy = GREATEST(0, energy + %s),
                   health = GREATEST(0, health + %s),
                   happiness = GREATEST(0, happiness + %s),
                   money = money + %s
               WHERE id = %s AND diamonds >= %s""",
            (diamond_cost, time_after,
             events_summary['energy_change'],
             events_summary['health_change'],
             events_summary['happiness_change'],
             events_summary['money_earned'],
             player_id, diamond_cost)
        )

        # Check if update succeeded (balance was sufficient)
        if cursor.rowcount == 0:
            conn.rollback()
            return {
                'success': False,
                'message': 'Insufficient diamonds (concurrent purchase or balance changed)'
            }

        # Get new balance after atomic update
        new_diamonds = player['diamonds'] - diamond_cost

        # Log transaction
        cursor.execute(
            """INSERT INTO time_skip_purchases
               (player_id, skip_type, diamond_cost, time_before, time_after, events_simulated)
               VALUES (%s, %s, %s, %s, %s, %s)""",
            (player_id, skip_type, diamond_cost, time_before, time_after,
             len(events_summary['events']))
        )

        conn.commit()

        logging.info(f"Player {player_id} skipped {skip_type} for {diamond_cost} diamonds")

        duration_hours = (time_after - time_before).total_seconds() / 3600

        return {
            'success': True,
            'message': 'Time skipped successfully',
            'summary': {
                'diamonds': new_diamonds,
                'new_time': time_after.isoformat(),
                'duration_hours': duration_hours,
                'events': events_summary['events'][:10],  # First 10 events
                'stat_changes': {
                    'money': events_summary['money_earned'],
                    'energy': events_summary['energy_change'],
                    'health': events_summary['health_change'],
                    'happiness': events_summary['happiness_change']
                }
            }
        }

    except Exception as e:
        if conn:
            conn.rollback()
        logging.error(f"Time skip error for player {player_id}: {e}", exc_info=True)
        return {
            'success': False,
            'message': 'Server error. Please try again.'
        }

    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()


def simulate_time_period(player_id: int, start_time: datetime,
                         end_time: datetime, cursor) -> Dict[str, Any]:
    """
    Simulate game events during time skip period.

    Args:
        player_id: The player's ID
        start_time: Start of simulation period
        end_time: End of simulation period
        cursor: Database cursor (for efficiency)

    Returns:
        Summary dict with events and stat changes
    """
    events = []
    money_earned = 0
    energy_change = 0
    health_change = 0
    happiness_change = 0

    # Get player's current state
    cursor.execute(
        """SELECT occupation, occupationSalary, educationLevel, age,
                  relationships
           FROM players WHERE id = %s""",
        (player_id,)
    )
    player_state = cursor.fetchone()

    if not player_state:
        return {
            'events': [],
            'money_earned': 0,
            'energy_change': 0,
            'health_change': 0,
            'happiness_change': 0
        }

    # Calculate simulation parameters
    current_time = start_time
    simulation_step = timedelta(hours=1)  # Simulate hour by hour

    hours_elapsed = 0
    work_hours = 0
    school_hours = 0

    while current_time < end_time and hours_elapsed < 168:  # Max 1 week
        hour_of_day = current_time.hour

        # Work hours (9am-5pm on weekdays)
        if player_state['occupation'] and hour_of_day >= 9 and hour_of_day < 17:
            if current_time.weekday() < 5:  # Monday-Friday
                # Earn money
                if player_state['occupationSalary']:
                    hourly_wage = player_state['occupationSalary'] / (40 * 4)  # Monthly to hourly
                    money_earned += hourly_wage
                    work_hours += 1

        # School hours (if in school)
        if player_state['educationLevel'] and hour_of_day >= 8 and hour_of_day < 15:
            if current_time.weekday() < 5:
                school_hours += 1

        # Sleep hours (recover energy)
        if hour_of_day >= 22 or hour_of_day < 6:
            energy_change += 2  # Recover 2 energy per sleep hour

        # Natural stat changes
        energy_change -= 0.5  # Energy depletes
        health_change -= 0.1  # Slight health decay
        happiness_change -= 0.2  # Slight happiness decay

        current_time += simulation_step
        hours_elapsed += 1

    # Create event summaries
    if work_hours > 0:
        events.append({
            'type': 'work',
            'description': f'Worked {work_hours} hours',
            'money_earned': int(money_earned)
        })

    if school_hours > 0:
        events.append({
            'type': 'school',
            'description': f'Attended {school_hours} hours of classes',
            'smarts_gained': school_hours // 2
        })

    # Cap stat changes
    energy_change = max(-50, min(50, energy_change))
    health_change = max(-20, min(10, health_change))
    happiness_change = max(-30, min(20, happiness_change))

    events.append({
        'type': 'summary',
        'description': f'Time advanced {hours_elapsed} hours',
        'stat_changes': {
            'energy': int(energy_change),
            'health': int(health_change),
            'happiness': int(happiness_change)
        }
    })

    return {
        'events': events,
        'money_earned': int(money_earned),
        'energy_change': int(energy_change),
        'health_change': int(health_change),
        'happiness_change': int(happiness_change)
    }


def handle_purchase_time_skip(player_id: int, message_data: Dict[str, Any], send_to_client):
    """
    WebSocket message handler for 'purchaseTimeSkip' messages.

    Args:
        player_id: The player's ID
        message_data: Message data containing 'skipType'
        send_to_client: Function to send message back to client
    """
    skip_type = message_data.get('skipType')

    if not skip_type:
        send_to_client(player_id, {
            'type': 'error',
            'error_code': 'INVALID_REQUEST',
            'message': 'Missing skipType'
        })
        return

    result = purchase_time_skip(player_id, skip_type)

    if result['success']:
        send_to_client(player_id, {
            'type': 'timeSkipComplete',
            'success': True,
            'summary': result['summary']
        })

        # Send full player state update
        send_to_client(player_id, {
            'type': 'requestFullUpdate'
        })
    else:
        send_to_client(player_id, {
            'type': 'error',
            'error_code': 'TIME_SKIP_FAILED',
            'message': result['message']
        })


def get_skip_tiers() -> Dict[str, Dict[str, Any]]:
    """
    Get all available time skip tiers.

    Returns:
        Dictionary of skip tiers
    """
    return {
        key: {
            'duration': value['duration'].total_seconds() if value['duration'] else None,
            'diamonds': value['diamonds']
        }
        for key, value in SKIP_TIERS.items()
    }
