"""
Daily Login Reward System

Tracks 7-day login streaks and awards diamonds, energy, items, or prestige.
Streak resets if player misses a day.
"""

from typing import Dict, Any, Optional
from datetime import date, timedelta
import logging
import random
import asyncio
from database.db_operations import get_database_connection


# Daily reward definitions (7-day cycle)
DAILY_REWARDS = [
    {'day': 1, 'type': 'diamonds', 'amount': 5, 'name': '5 Diamonds'},
    {'day': 2, 'type': 'diamonds', 'amount': 10, 'name': '10 Diamonds'},
    {'day': 3, 'type': 'energy', 'amount': 50, 'name': '50 Energy'},
    {'day': 4, 'type': 'diamonds', 'amount': 15, 'name': '15 Diamonds'},
    {'day': 5, 'type': 'diamonds', 'amount': 20, 'name': '20 Diamonds + Item'},
    {'day': 6, 'type': 'diamonds', 'amount': 25, 'name': '25 Diamonds'},
    {'day': 7, 'type': 'diamonds', 'amount': 50, 'name': '50 Diamonds Bonus'},
]


async def initialize_daily_rewards():
    """
    Insert reward definitions into database.
    Called during server startup.
    Uses async database pool for proper connection management.
    """
    from database_async import execute_query

    try:
        for reward in DAILY_REWARDS:
            await execute_query(
                """INSERT INTO daily_login_rewards
                   (day_number, reward_type, reward_amount, display_name)
                   VALUES (%s, %s, %s, %s) AS new_reward
                   ON DUPLICATE KEY UPDATE
                   reward_amount=new_reward.reward_amount,
                   display_name=new_reward.display_name""",
                (reward['day'], reward['type'], reward['amount'], reward['name'])
            )

        logging.info(f"Initialized {len(DAILY_REWARDS)} daily login rewards")

    except Exception as e:
        logging.error(f"Error initializing daily rewards: {e}", exc_info=True)


def check_daily_login(player_id: int) -> Dict[str, Any]:
    """
    Check and update daily login streak.
    Called when player connects to server.

    Args:
        player_id: The player's ID

    Returns:
        dict with keys:
        - reward_available: bool, whether reward can be claimed
        - streak: int, current streak count
        - reward: dict or None, today's reward details
        - streak_broken: bool, whether streak was broken today
    """
    conn = None
    cursor = None
    today = date.today()

    try:
        conn = get_database_connection()
        cursor = conn.cursor(dictionary=True)

        # Get player's streak data
        cursor.execute(
            "SELECT * FROM player_login_streak WHERE player_id = %s",
            (player_id,)
        )
        streak_data = cursor.fetchone()

        # First time login - create streak record
        if not streak_data:
            cursor.execute(
                """INSERT INTO player_login_streak
                   (player_id, current_streak, last_login_date, total_logins, next_reward_day)
                   VALUES (%s, 1, %s, 1, 1)""",
                (player_id, today)
            )
            conn.commit()

            reward = get_daily_reward(1)

            logging.info(f"Player {player_id} first login - starting streak")

            return {
                'reward_available': True,
                'streak': 1,
                'reward': reward,
                'streak_broken': False
            }

        last_login = streak_data['last_login_date']

        # Check if already logged in today
        if last_login == today:
            return {
                'reward_available': False,
                'streak': streak_data['current_streak'],
                'reward': None,
                'streak_broken': False
            }

        # Check if streak broken (more than 1 day gap)
        days_since_login = (today - last_login).days
        streak_broken = False

        if days_since_login == 1:
            # Streak continues
            new_streak = streak_data['current_streak'] + 1
            next_day = (streak_data['next_reward_day'] % 7) + 1
        else:
            # Streak broken, restart
            new_streak = 1
            next_day = 1
            streak_broken = True
            logging.info(f"Player {player_id} streak broken after {days_since_login} days")

        # Update streak
        cursor.execute(
            """UPDATE player_login_streak
               SET current_streak = %s, last_login_date = %s,
                   total_logins = total_logins + 1, next_reward_day = %s
               WHERE player_id = %s""",
            (new_streak, today, next_day, player_id)
        )
        conn.commit()

        # Get today's reward (use the OLD next_reward_day before we incremented it)
        reward = get_daily_reward(streak_data['next_reward_day'])

        logging.info(f"Player {player_id} daily login - streak: {new_streak}, day: {streak_data['next_reward_day']}")

        return {
            'reward_available': True,
            'streak': new_streak,
            'reward': reward,
            'streak_broken': streak_broken
        }

    except Exception as e:
        logging.error(f"Error checking daily login for player {player_id}: {e}", exc_info=True)
        return {
            'reward_available': False,
            'streak': 0,
            'reward': None,
            'streak_broken': False
        }

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


def get_daily_reward(day_number: int) -> Optional[Dict[str, Any]]:
    """
    Get reward for specific day.

    Args:
        day_number: Day number (1-7)

    Returns:
        Dict with reward details or None if not found
    """
    conn = None
    cursor = None

    try:
        conn = get_database_connection()
        cursor = conn.cursor(dictionary=True)

        cursor.execute(
            "SELECT * FROM daily_login_rewards WHERE day_number = %s",
            (day_number,)
        )
        reward = cursor.fetchone()

        if not reward:
            logging.warning(f"Daily reward not found for day {day_number}")
            return None

        return {
            'day': reward['day_number'],
            'type': reward['reward_type'],
            'amount': reward['reward_amount'],
            'item_id': reward.get('reward_item_id'),
            'name': reward['display_name']
        }

    except Exception as e:
        logging.error(f"Error getting daily reward for day {day_number}: {e}", exc_info=True)
        return None

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


def claim_daily_reward(player_id: int) -> Dict[str, Any]:
    """
    Claim today's reward.
    Awards the reward to player and marks as claimed.

    Args:
        player_id: The player's ID

    Returns:
        dict with keys:
        - success: bool
        - reward: dict or None
        - message: str
    """
    conn = None
    cursor = None

    try:
        conn = get_database_connection()
        cursor = conn.cursor(dictionary=True)

        # Get streak data
        cursor.execute(
            "SELECT * FROM player_login_streak WHERE player_id = %s",
            (player_id,)
        )
        streak_data = cursor.fetchone()

        if not streak_data:
            return {
                'success': False,
                'reward': None,
                'message': 'No login streak found'
            }

        # Check if already claimed today
        if streak_data['last_login_date'] == date.today():
            # Already logged in today, check if this is a duplicate claim attempt
            # In a real implementation, we'd track claim separately
            # For now, we allow claiming on first login of the day
            pass

        # Calculate which reward day to use
        # Use next_reward_day - 1 because it was already incremented during check_daily_login
        # Actually, let's use the current next_reward_day minus 1, or just use the stored day
        reward_day = streak_data['next_reward_day'] if streak_data['next_reward_day'] > 0 else 1

        # Get the reward
        reward = get_daily_reward(reward_day)

        if not reward:
            return {
                'success': False,
                'reward': None,
                'message': 'Reward not found'
            }

        # Award based on type
        if reward['type'] == 'diamonds':
            from monetization.diamond_economy import award_diamonds
            award_diamonds(player_id, f"daily_reward_day{reward_day}", reward['amount'])

        elif reward['type'] == 'energy':
            cursor.execute(
                "UPDATE players SET energy = LEAST(energy + %s, max_energy) WHERE id = %s",
                (reward['amount'], player_id)
            )
            conn.commit()

        elif reward['type'] == 'prestige':
            cursor.execute(
                "UPDATE players SET prestige = prestige + %s WHERE id = %s",
                (reward['amount'], player_id)
            )
            conn.commit()

        elif reward['type'] == 'item':
            # Award random luxury item (if store_items table exists)
            cursor.execute(
                "SELECT * FROM store_items WHERE category = 'luxury' ORDER BY RAND() LIMIT 1"
            )
            luxury_items = cursor.fetchall()

            if luxury_items:
                item = luxury_items[0]
                # Add to player inventory
                cursor.execute(
                    """INSERT INTO player_inventory (player_id, item_id, quantity)
                       VALUES (%s, %s, 1)
                       ON DUPLICATE KEY UPDATE quantity = quantity + 1""",
                    (player_id, item['id'])
                )
                conn.commit()
                logging.info(f"Player {player_id} received luxury item: {item.get('name', 'unknown')}")

        logging.info(f"Player {player_id} claimed daily reward: Day {reward_day}")

        return {
            'success': True,
            'reward': reward,
            'message': 'Reward claimed successfully'
        }

    except Exception as e:
        if conn:
            conn.rollback()
        logging.error(f"Error claiming daily reward for player {player_id}: {e}", exc_info=True)
        return {
            'success': False,
            'reward': None,
            'message': 'Server error'
        }

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


def get_daily_reward_state(player_id: int) -> Dict[str, Any]:
    """
    Get complete daily reward state for iOS DailyRewardState model.

    Args:
        player_id: The player's ID

    Returns:
        Dictionary matching iOS DailyRewardState structure
    """
    conn = None
    cursor = None
    today = date.today()

    try:
        conn = get_database_connection()
        cursor = conn.cursor(dictionary=True)

        # Get player's streak info
        cursor.execute(
            """SELECT current_streak, last_login_date, next_reward_day
               FROM player_login_streak
               WHERE player_id = %s""",
            (player_id,)
        )
        streak_info = cursor.fetchone()

        if not streak_info:
            # First time login - initialize
            current_streak = 1
            last_login = None
            next_reward_day = 1
        else:
            current_streak = streak_info['current_streak']
            last_login = streak_info['last_login_date']
            next_reward_day = streak_info['next_reward_day']

        # Check if already logged in/claimed today
        todays_claimed = last_login == today if last_login else False
        can_claim = not todays_claimed

        # Get all 7 rewards
        cursor.execute(
            """SELECT day_number, reward_type, reward_amount, display_name
               FROM daily_login_rewards
               ORDER BY day_number"""
        )
        reward_definitions = cursor.fetchall()

        # Format rewards array matching iOS DayReward model
        rewards = []
        for reward_def in reward_definitions:
            day_num = reward_def['day_number']
            reward_type = reward_def['reward_type']
            amount = reward_def['reward_amount']

            # Check if this day has been claimed
            claimed = day_num < next_reward_day or (day_num == next_reward_day and todays_claimed)

            day_reward = {
                'id': day_num,
                'diamonds': amount if reward_type == 'diamonds' else 0,
                'energy': amount if reward_type == 'energy' else None,
                'money': amount if reward_type == 'money' else None,
                'bonusItem': 'Luxury Item' if day_num == 5 else None,
                'claimed': claimed
            }
            rewards.append(day_reward)

        # Calculate next reset (tomorrow midnight)
        tomorrow = today + timedelta(days=1)
        from datetime import datetime
        next_reset = datetime.combine(tomorrow, datetime.min.time()).isoformat()
        last_login_str = last_login.isoformat() if last_login else today.isoformat()

        return {
            'currentStreak': current_streak,
            'lastLoginDate': last_login_str,
            'nextResetDate': next_reset,
            'canClaim': can_claim,
            'todaysClaimed': todays_claimed,
            'rewards': rewards
        }

    except Exception as e:
        logging.error(f"Error getting daily reward state for player {player_id}: {e}", exc_info=True)
        # Return default state
        from datetime import datetime
        tomorrow = today + timedelta(days=1)
        return {
            'currentStreak': 0,
            'lastLoginDate': today.isoformat(),
            'nextResetDate': datetime.combine(tomorrow, datetime.min.time()).isoformat(),
            'canClaim': True,
            'todaysClaimed': False,
            'rewards': []
        }

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


def handle_daily_login_check(player_id: int, send_to_client):
    """
    WebSocket handler for daily login check.
    Called when player connects to server.

    Args:
        player_id: The player's ID
        send_to_client: Function to send messages to client (player_id, message_dict)
    """
    try:
        # Check and update streak
        check_daily_login(player_id)

        # Get complete state for iOS
        state = get_daily_reward_state(player_id)

        # Send complete state matching iOS DailyRewardState model
        send_to_client(player_id, {
            'type': 'dailyRewardStatus',
            **state  # Spread operator to include all state fields
        })

        logging.info(f"Sent daily reward state to player {player_id}")

    except Exception as e:
        logging.error(f"Error handling daily login check for player {player_id}: {e}", exc_info=True)


def get_login_streak_info(player_id: int) -> Dict[str, Any]:
    """
    Get player's login streak information.

    Args:
        player_id: The player's ID

    Returns:
        dict with streak info
    """
    conn = None
    cursor = None

    try:
        conn = get_database_connection()
        cursor = conn.cursor(dictionary=True)

        cursor.execute(
            "SELECT * FROM player_login_streak WHERE player_id = %s",
            (player_id,)
        )
        streak_data = cursor.fetchone()

        if not streak_data:
            return {
                'current_streak': 0,
                'total_logins': 0,
                'next_reward_day': 1,
                'last_login_date': None
            }

        return {
            'current_streak': streak_data['current_streak'],
            'total_logins': streak_data['total_logins'],
            'next_reward_day': streak_data['next_reward_day'],
            'last_login_date': streak_data['last_login_date'].isoformat() if streak_data['last_login_date'] else None
        }

    except Exception as e:
        logging.error(f"Error getting streak info for player {player_id}: {e}", exc_info=True)
        return {
            'current_streak': 0,
            'total_logins': 0,
            'next_reward_day': 1,
            'last_login_date': None
        }

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


def get_all_rewards() -> list:
    """
    Get all daily reward definitions.

    Returns:
        List of reward dictionaries
    """
    conn = None
    cursor = None

    try:
        conn = get_database_connection()
        cursor = conn.cursor(dictionary=True)

        cursor.execute(
            "SELECT * FROM daily_login_rewards ORDER BY day_number"
        )

        return cursor.fetchall()

    except Exception as e:
        logging.error(f"Error getting all rewards: {e}", exc_info=True)
        return []

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