"""
Achievement System

Tracks and unlocks achievements based on player actions.
Includes 40+ achievements across multiple categories.
"""

from typing import Dict, Any, List, Optional
import logging
import mysql.connector.errors
from database import get_database_connection

# Setup logging
logger = logging.getLogger(__name__)

# Achievement definitions (40+ achievements)
ACHIEVEMENT_DEFINITIONS = [
    # === LIFE MILESTONES ===
    {'key': 'first_steps', 'name': 'First Steps', 'desc': 'Complete the onboarding tutorial',
     'category': 'life_milestone', 'reward': 25, 'icon': 'graduationcap', 'hidden': False},
    {'key': 'first_day_school', 'name': 'First Day of School', 'desc': 'Start elementary school',
     'category': 'life_milestone', 'reward': 10, 'icon': 'book', 'hidden': False},
    {'key': 'graduate_hs', 'name': 'High School Graduate', 'desc': 'Graduate from high school',
     'category': 'life_milestone', 'reward': 25, 'icon': 'graduationcap', 'hidden': False},
    {'key': 'graduate_college', 'name': 'College Degree', 'desc': 'Graduate from college',
     'category': 'life_milestone', 'reward': 50, 'icon': 'scroll', 'hidden': False},
    {'key': 'graduate_masters', 'name': 'Master Scholar', 'desc': 'Complete a master\'s degree',
     'category': 'life_milestone', 'reward': 75, 'icon': 'brain', 'hidden': False},
    {'key': 'graduate_phd', 'name': 'Doctor of Philosophy', 'desc': 'Earn a PhD',
     'category': 'life_milestone', 'reward': 100, 'icon': 'crown', 'hidden': False},
    {'key': 'get_married', 'name': 'Happily Ever After', 'desc': 'Get married',
     'category': 'life_milestone', 'reward': 30, 'icon': 'heart', 'hidden': False},
    {'key': 'have_child', 'name': 'New Parent', 'desc': 'Have your first child',
     'category': 'life_milestone', 'reward': 40, 'icon': 'figure.2', 'hidden': False},
    {'key': 'live_to_50', 'name': 'Half Century', 'desc': 'Live to 50 years old',
     'category': 'life_milestone', 'reward': 20, 'icon': 'star', 'hidden': False},
    {'key': 'live_to_100', 'name': 'Century Club', 'desc': 'Live to 100 years old',
     'category': 'life_milestone', 'reward': 200, 'icon': 'star.fill', 'hidden': False},

    # === CAREER ===
    {'key': 'first_job', 'name': 'Working Class', 'desc': 'Get your first job',
     'category': 'career', 'reward': 10, 'icon': 'briefcase', 'hidden': False},
    {'key': 'promotion', 'name': 'Climbing the Ladder', 'desc': 'Get promoted',
     'category': 'career', 'reward': 20, 'icon': 'arrow.up', 'hidden': False},
    {'key': 'become_manager', 'name': 'Management Material', 'desc': 'Become a manager',
     'category': 'career', 'reward': 30, 'icon': 'person.2', 'hidden': False},
    {'key': 'become_ceo', 'name': 'Corner Office', 'desc': 'Become a CEO',
     'category': 'career', 'reward': 75, 'icon': 'crown', 'hidden': False},
    {'key': 'earn_100k', 'name': 'Six Figures', 'desc': 'Earn $100,000 in a year',
     'category': 'career', 'reward': 50, 'icon': 'dollarsign.circle', 'hidden': False},
    {'key': 'earn_1m_lifetime', 'name': 'Millionaire', 'desc': 'Earn $1,000,000 in your lifetime',
     'category': 'career', 'reward': 100, 'icon': 'banknote', 'hidden': False},
    {'key': 'earn_10m_lifetime', 'name': 'Multi-Millionaire', 'desc': 'Earn $10,000,000 in your lifetime',
     'category': 'career', 'reward': 250, 'icon': 'banknote.fill', 'hidden': False},
    {'key': 'perfect_performance', 'name': 'Employee of the Year', 'desc': 'Achieve 100% job performance',
     'category': 'career', 'reward': 25, 'icon': 'trophy', 'hidden': False},

    # === RELATIONSHIPS ===
    {'key': 'make_first_friend', 'name': 'Social Butterfly Begins', 'desc': 'Make your first friend',
     'category': 'relationship', 'reward': 10, 'icon': 'person', 'hidden': False},
    {'key': 'best_friend', 'name': 'Best Friends Forever', 'desc': 'Reach 100 affinity with someone',
     'category': 'relationship', 'reward': 30, 'icon': 'heart.fill', 'hidden': False},
    {'key': 'date_10_people', 'name': 'Dating Around', 'desc': 'Date 10 different people',
     'category': 'relationship', 'reward': 25, 'icon': 'heart.multiple', 'hidden': False},
    {'key': 'first_kiss', 'name': 'First Kiss', 'desc': 'Share your first kiss',
     'category': 'relationship', 'reward': 15, 'icon': 'heart.circle', 'hidden': False},
    {'key': 'golden_anniversary', 'name': 'Golden Anniversary', 'desc': 'Stay married for 50 years',
     'category': 'relationship', 'reward': 100, 'icon': 'sparkles', 'hidden': False},
    {'key': 'five_children', 'name': 'Big Family', 'desc': 'Have 5 children',
     'category': 'relationship', 'reward': 50, 'icon': 'house.fill', 'hidden': False},
    {'key': 'popular', 'name': 'Mr/Ms Popular', 'desc': 'Have 10 friends',
     'category': 'relationship', 'reward': 35, 'icon': 'person.3', 'hidden': False},

    # === COLLECTION ===
    {'key': 'first_purchase', 'name': 'First Purchase', 'desc': 'Buy your first item',
     'category': 'collection', 'reward': 5, 'icon': 'bag', 'hidden': False},
    {'key': 'own_25_items', 'name': 'Collector', 'desc': 'Own 25 items',
     'category': 'collection', 'reward': 20, 'icon': 'square.grid.3x3', 'hidden': False},
    {'key': 'own_50_items', 'name': 'Hoarder', 'desc': 'Own 50 items',
     'category': 'collection', 'reward': 40, 'icon': 'square.grid.4x3', 'hidden': False},
    {'key': 'own_100_items', 'name': 'Ultimate Collector', 'desc': 'Own 100 items',
     'category': 'collection', 'reward': 80, 'icon': 'square.stack.3d.up', 'hidden': False},
    {'key': 'prestige_100', 'name': 'Rising Star', 'desc': 'Reach 100 prestige',
     'category': 'collection', 'reward': 25, 'icon': 'star', 'hidden': False},
    {'key': 'prestige_500', 'name': 'Celebrity Status', 'desc': 'Reach 500 prestige',
     'category': 'collection', 'reward': 75, 'icon': 'star.circle', 'hidden': False},
    {'key': 'max_prestige', 'name': 'Maximum Prestige', 'desc': 'Reach 1000 prestige',
     'category': 'collection', 'reward': 150, 'icon': 'star.circle.fill', 'hidden': False},

    # === SECRET ACHIEVEMENTS ===
    {'key': 'die_at_69', 'name': 'Nice', 'desc': 'Die at exactly 69 years old',
     'category': 'secret', 'reward': 50, 'icon': 'face.smiling', 'hidden': True},
    {'key': 'fired_3_times', 'name': 'Professional Quitter', 'desc': 'Get fired 3 times',
     'category': 'secret', 'reward': 25, 'icon': 'xmark.circle', 'hidden': True},
    {'key': 'never_marry', 'name': 'Forever Alone', 'desc': 'Complete a life without marrying',
     'category': 'secret', 'reward': 30, 'icon': 'person.fill', 'hidden': True},
    {'key': 'marry_3_times', 'name': 'Serial Monogamist', 'desc': 'Get married 3 different times',
     'category': 'secret', 'reward': 40, 'icon': 'arrow.triangle.2.circlepath', 'hidden': True},
    {'key': 'die_poor', 'name': 'Broke at Death', 'desc': 'Die with less than $100',
     'category': 'secret', 'reward': 20, 'icon': 'banknote.slash', 'hidden': True},
    {'key': 'die_rich', 'name': 'Died Wealthy', 'desc': 'Die with over $1,000,000',
     'category': 'secret', 'reward': 100, 'icon': 'banknote.fill', 'hidden': True},
    {'key': 'perfect_health', 'name': 'Health Nut', 'desc': 'Maintain 100% health for a full year',
     'category': 'secret', 'reward': 50, 'icon': 'heart.text.square.fill', 'hidden': True},
    {'key': 'workaholic', 'name': 'Workaholic', 'desc': 'Work 80+ hours in a week',
     'category': 'secret', 'reward': 30, 'icon': 'deskclock', 'hidden': True},
    {'key': 'early_retirement', 'name': 'Early Retirement', 'desc': 'Retire before age 40',
     'category': 'secret', 'reward': 75, 'icon': 'beach.umbrella', 'hidden': True},
    {'key': 'straight_a', 'name': 'Straight A Student', 'desc': 'Graduate with a 4.0 GPA',
     'category': 'secret', 'reward': 40, 'icon': 'a.circle.fill', 'hidden': True},
    {'key': 'dropout', 'name': 'School Dropout', 'desc': 'Drop out of high school',
     'category': 'secret', 'reward': 15, 'icon': 'book.closed', 'hidden': True},
    {'key': 'no_friends', 'name': 'Lone Wolf', 'desc': 'Reach age 30 without making any friends',
     'category': 'secret', 'reward': 25, 'icon': 'person.fill.questionmark', 'hidden': True},
]


def initialize_achievements():
    """Insert achievement definitions into database."""
    conn = None
    cursor = None

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

        for ach in ACHIEVEMENT_DEFINITIONS:
            cursor.execute(
                """INSERT INTO achievements
                   (key_name, display_name, description, category, diamond_reward, icon_name, hidden)
                   VALUES (%s, %s, %s, %s, %s, %s, %s) AS new_ach
                   ON DUPLICATE KEY UPDATE
                   display_name=new_ach.display_name,
                   description=new_ach.description,
                   diamond_reward=new_ach.diamond_reward""",
                (ach['key'], ach['name'], ach['desc'], ach['category'],
                 ach['reward'], ach['icon'], ach['hidden'])
            )

        conn.commit()
        logging.info(f"Initialized {len(ACHIEVEMENT_DEFINITIONS)} achievements")

    except Exception as e:
        if conn:
            conn.rollback()
        logging.error(f"Error initializing achievements: {e}", exc_info=True)

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


def check_achievements(player_id: int, event_type: str, event_data: Dict[str, Any] = None) -> List[Dict]:
    """
    Check if any achievements should be unlocked based on event.

    Args:
        player_id: The player's ID
        event_type: Type of event that occurred
        event_data: Additional event data

    Returns:
        List of unlocked achievements
    """
    if event_data is None:
        event_data = {}

    unlocked = []
    conn = None
    cursor = None

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

        # Get player's current state for conditional checks
        # Note: This uses a normalized 'players' table that may not exist yet
        # in pickle-based save game systems. Gracefully skip if not available.
        try:
            cursor.execute(
                """SELECT age, money, diamonds, prestige, health, happiness,
                          educationLevel, occupation, occupationSalary
                   FROM players WHERE id = %s""",
                (player_id,)
            )
            player = cursor.fetchone()

            if not player:
                return []
        except mysql.connector.errors.ProgrammingError as e:
            if '42S02' in str(e):  # Table doesn't exist
                logger.warning(f"Players table not found - achievements disabled until migration runs")
                return []
            raise

        # Get player statistics
        cursor.execute(
            "SELECT * FROM player_statistics WHERE player_id = %s",
            (player_id,)
        )
        stats = cursor.fetchone()

        # Event-specific checks
        if event_type == 'start_school':
            unlocked.extend(check_and_unlock(player_id, 'first_day_school', cursor, conn))

        elif event_type == 'graduate':
            level = event_data.get('level', '')
            if 'high_school' in level.lower():
                unlocked.extend(check_and_unlock(player_id, 'graduate_hs', cursor, conn))

                # Check GPA for straight A
                if event_data.get('gpa', 0) >= 4.0:
                    unlocked.extend(check_and_unlock(player_id, 'straight_a', cursor, conn))

            elif 'college' in level.lower() or 'university' in level.lower():
                unlocked.extend(check_and_unlock(player_id, 'graduate_college', cursor, conn))
            elif 'master' in level.lower():
                unlocked.extend(check_and_unlock(player_id, 'graduate_masters', cursor, conn))
            elif 'phd' in level.lower() or 'doctorate' in level.lower():
                unlocked.extend(check_and_unlock(player_id, 'graduate_phd', cursor, conn))

        elif event_type == 'get_job':
            if stats and stats['job_count'] == 1:
                unlocked.extend(check_and_unlock(player_id, 'first_job', cursor, conn))

        elif event_type == 'promotion':
            unlocked.extend(check_and_unlock(player_id, 'promotion', cursor, conn))

            # Check title-based achievements
            title = event_data.get('title', '').lower()
            if 'manager' in title:
                unlocked.extend(check_and_unlock(player_id, 'become_manager', cursor, conn))
            elif 'ceo' in title or 'chief executive' in title:
                unlocked.extend(check_and_unlock(player_id, 'become_ceo', cursor, conn))

        elif event_type == 'marriage':
            unlocked.extend(check_and_unlock(player_id, 'get_married', cursor, conn))

            # Check for multiple marriages
            if stats and stats['ever_married']:
                # Count previous marriages (simplified)
                unlocked.extend(check_and_unlock(player_id, 'marry_3_times', cursor, conn))

        elif event_type == 'birth_child':
            if stats and stats['children_count'] == 1:
                unlocked.extend(check_and_unlock(player_id, 'have_child', cursor, conn))
            elif stats and stats['children_count'] >= 5:
                unlocked.extend(check_and_unlock(player_id, 'five_children', cursor, conn))

        elif event_type == 'first_kiss':
            unlocked.extend(check_and_unlock(player_id, 'first_kiss', cursor, conn))

        elif event_type == 'birthday':
            age = event_data.get('age', player['age'])
            if age == 50:
                unlocked.extend(check_and_unlock(player_id, 'live_to_50', cursor, conn))
            elif age == 69:
                unlocked.extend(check_and_unlock(player_id, 'die_at_69', cursor, conn))
            elif age == 100:
                unlocked.extend(check_and_unlock(player_id, 'live_to_100', cursor, conn))

        elif event_type == 'death':
            # Check death-related achievements
            if player['money'] < 100:
                unlocked.extend(check_and_unlock(player_id, 'die_poor', cursor, conn))
            elif player['money'] >= 1000000:
                unlocked.extend(check_and_unlock(player_id, 'die_rich', cursor, conn))

            if stats:
                if not stats['ever_married']:
                    unlocked.extend(check_and_unlock(player_id, 'never_marry', cursor, conn))

                if stats['lifetime_earnings'] >= 1000000:
                    unlocked.extend(check_and_unlock(player_id, 'earn_1m_lifetime', cursor, conn))
                elif stats['lifetime_earnings'] >= 10000000:
                    unlocked.extend(check_and_unlock(player_id, 'earn_10m_lifetime', cursor, conn))

        elif event_type == 'make_friend':
            if stats and stats['friends_count'] == 1:
                unlocked.extend(check_and_unlock(player_id, 'make_first_friend', cursor, conn))
            elif stats and stats['friends_count'] >= 10:
                unlocked.extend(check_and_unlock(player_id, 'popular', cursor, conn))

        elif event_type == 'purchase_item':
            # Check item count from inventory
            cursor.execute(
                "SELECT COUNT(DISTINCT item_id) as item_count FROM player_inventory WHERE player_id = %s",
                (player_id,)
            )
            result = cursor.fetchone()
            item_count = result['item_count'] if result else 0

            if item_count == 1:
                unlocked.extend(check_and_unlock(player_id, 'first_purchase', cursor, conn))
            elif item_count >= 25:
                unlocked.extend(check_and_unlock(player_id, 'own_25_items', cursor, conn))
            elif item_count >= 50:
                unlocked.extend(check_and_unlock(player_id, 'own_50_items', cursor, conn))
            elif item_count >= 100:
                unlocked.extend(check_and_unlock(player_id, 'own_100_items', cursor, conn))

        elif event_type == 'affinity_milestone':
            affinity = event_data.get('affinity', 0)
            if affinity >= 100:
                unlocked.extend(check_and_unlock(player_id, 'best_friend', cursor, conn))

        elif event_type == 'fired':
            if stats and stats['times_fired'] >= 3:
                unlocked.extend(check_and_unlock(player_id, 'fired_3_times', cursor, conn))

        # Continuous checks (can be triggered by any event)
        # Prestige milestones
        if player['prestige'] >= 100:
            unlocked.extend(check_and_unlock(player_id, 'prestige_100', cursor, conn))
        if player['prestige'] >= 500:
            unlocked.extend(check_and_unlock(player_id, 'prestige_500', cursor, conn))
        if player['prestige'] >= 1000:
            unlocked.extend(check_and_unlock(player_id, 'max_prestige', cursor, conn))

        # Dating milestone
        if stats and stats['people_dated'] >= 10:
            unlocked.extend(check_and_unlock(player_id, 'date_10_people', cursor, conn))

        # Marriage duration
        if stats and stats['years_married'] >= 50:
            unlocked.extend(check_and_unlock(player_id, 'golden_anniversary', cursor, conn))

        return unlocked

    except Exception as e:
        logging.error(f"Error checking achievements for player {player_id}: {e}", exc_info=True)
        return []

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


def check_and_unlock(player_id: int, achievement_key: str, cursor, conn) -> List[Dict]:
    """
    Check if player has unlocked achievement. If not yet unlocked, unlock it.

    Args:
        player_id: The player's ID
        achievement_key: Achievement key name
        cursor: Database cursor (for efficiency)
        conn: Database connection (for commit)

    Returns:
        List containing the achievement dict if newly unlocked, empty list otherwise
    """
    try:
        # Get achievement
        cursor.execute(
            "SELECT * FROM achievements WHERE key_name = %s",
            (achievement_key,)
        )
        achievement = cursor.fetchone()

        if not achievement:
            logging.warning(f"Achievement not found: {achievement_key}")
            return []

        # Check if player already has it
        cursor.execute(
            """SELECT * FROM player_achievements
               WHERE player_id = %s AND achievement_id = %s AND unlocked = TRUE""",
            (player_id, achievement['id'])
        )
        player_ach = cursor.fetchone()

        if player_ach:
            return []  # Already unlocked

        # Unlock it
        cursor.execute(
            """INSERT INTO player_achievements
               (player_id, achievement_id, progress, unlocked, unlock_date)
               VALUES (%s, %s, %s, TRUE, NOW())
               ON DUPLICATE KEY UPDATE unlocked = TRUE, unlock_date = NOW()""",
            (player_id, achievement['id'], achievement['progress_max'])
        )

        # Award diamonds
        from monetization.diamond_economy import award_diamonds
        award_diamonds(player_id, f"achievement_{achievement_key}", achievement['diamond_reward'])

        conn.commit()

        logging.info(f"Player {player_id} unlocked achievement: {achievement_key}")

        return [{
            'id': achievement['id'],
            'key': achievement['key_name'],
            'name': achievement['display_name'],
            'description': achievement['description'],
            'icon': achievement['icon_name'],
            'reward': achievement['diamond_reward']
        }]

    except Exception as e:
        logging.error(f"Error unlocking achievement {achievement_key}: {e}", exc_info=True)
        return []


def get_player_achievements(player_id: int) -> Dict[str, Any]:
    """
    Get all achievements and player's progress.

    Args:
        player_id: The player's ID

    Returns:
        Dict with 'unlocked' and 'locked' achievement lists
    """
    conn = None
    cursor = None

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

        # Get unlocked achievements
        cursor.execute(
            """SELECT a.*, pa.unlock_date
               FROM achievements a
               JOIN player_achievements pa ON a.id = pa.achievement_id
               WHERE pa.player_id = %s AND pa.unlocked = TRUE
               ORDER BY pa.unlock_date DESC""",
            (player_id,)
        )
        unlocked = cursor.fetchall()

        # Get locked achievements (non-hidden only)
        cursor.execute(
            """SELECT a.*
               FROM achievements a
               WHERE a.id NOT IN (
                   SELECT achievement_id FROM player_achievements
                   WHERE player_id = %s AND unlocked = TRUE
               )
               AND a.hidden = FALSE
               ORDER BY a.category, a.diamond_reward""",
            (player_id,)
        )
        locked = cursor.fetchall()

        return {
            'unlocked': unlocked,
            'locked': locked,
            'total_count': len(ACHIEVEMENT_DEFINITIONS),
            'unlocked_count': len(unlocked),
            'progress_percent': int((len(unlocked) / len(ACHIEVEMENT_DEFINITIONS)) * 100)
        }

    except Exception as e:
        logging.error(f"Error getting achievements for player {player_id}: {e}", exc_info=True)
        return {'unlocked': [], 'locked': [], 'total_count': 0, 'unlocked_count': 0, 'progress_percent': 0}

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