"""
Dating match logic with compatibility scoring.

This module handles:
- Attempting matches between player and NPCs
- Recording match attempts in database
- Integrating compatibility algorithm
- Supporting serendipity (random matches)
"""

import random
from typing import Dict, Optional
from database import get_database_connection
from .compatibility import calculate_compatibility


def get_person(person_id: int) -> Optional[Dict]:
    """
    Get person data from database by ID.

    Args:
        person_id: The person's database ID

    Returns:
        Dictionary with person data or None if not found
    """
    conn = get_database_connection()
    try:
        cursor = conn.cursor(dictionary=True)
        cursor.execute("""
            SELECT id, firstname, lastname, sex, age_years,
                   prestige, education_level, interests as likes
            FROM persons
            WHERE id = %s
        """, (person_id,))
        result = cursor.fetchone()
        return result
    finally:
        conn.close()


def create_match(player_id: int, target_id: int, compatibility: int) -> bool:
    """
    Create a successful match record in the database.

    Args:
        player_id: Player's ID
        target_id: Match target's ID
        compatibility: Compatibility score

    Returns:
        True if match was created successfully
    """
    conn = get_database_connection()
    try:
        cursor = conn.cursor()
        cursor.execute("""
            INSERT INTO match_attempts
            (player_id, target_id, compatibility_score, success)
            VALUES (%s, %s, %s, %s)
        """, (player_id, target_id, compatibility, True))
        conn.commit()
        return True
    except Exception as e:
        print(f"Error creating match: {e}")
        conn.rollback()
        return False
    finally:
        conn.close()


def record_failed_match(player_id: int, target_id: int, compatibility: int) -> bool:
    """
    Record a failed match attempt in the database.

    Args:
        player_id: Player's ID
        target_id: Match target's ID
        compatibility: Compatibility score

    Returns:
        True if record was created successfully
    """
    conn = get_database_connection()
    try:
        cursor = conn.cursor()
        cursor.execute("""
            INSERT INTO match_attempts
            (player_id, target_id, compatibility_score, success)
            VALUES (%s, %s, %s, %s)
        """, (player_id, target_id, compatibility, False))
        conn.commit()
        return True
    except Exception as e:
        print(f"Error recording failed match: {e}")
        conn.rollback()
        return False
    finally:
        conn.close()


def attempt_match(player_id: int, target_id: int) -> Dict:
    """
    Attempt to match with target using compatibility algorithm.

    The match succeeds if:
    - Compatibility score > 60, OR
    - Random "serendipity" factor (20% chance)

    Args:
        player_id: Player's ID
        target_id: Target person's ID

    Returns:
        Dictionary with match result:
        {
            'success': bool,
            'compatibility': int,
            'reason': str (optional)
        }
    """
    # Get person data
    player = get_person(player_id)
    target = get_person(target_id)

    if not player or not target:
        return {
            'success': False,
            'compatibility': 0,
            'reason': 'Person not found'
        }

    # Calculate compatibility
    compatibility = calculate_compatibility(player, target)

    # Determine if match succeeds
    # Match if score > 60, or allow 20% random matches (serendipity!)
    serendipity = random.random() < 0.2
    success = compatibility > 60 or serendipity

    # Record the match attempt
    if success:
        create_match(player_id, target_id, compatibility)
        reason = 'serendipity' if serendipity and compatibility <= 60 else 'compatibility'
        return {
            'success': True,
            'compatibility': compatibility,
            'reason': reason
        }
    else:
        record_failed_match(player_id, target_id, compatibility)
        return {
            'success': False,
            'compatibility': compatibility,
            'reason': 'low_compatibility'
        }


def get_match_history(player_id: int, limit: int = 10) -> list:
    """
    Get player's recent match attempts.

    Args:
        player_id: Player's ID
        limit: Maximum number of records to return

    Returns:
        List of match attempt dictionaries
    """
    conn = get_database_connection()
    try:
        cursor = conn.cursor(dictionary=True)
        cursor.execute("""
            SELECT ma.*, p.firstname, p.lastname
            FROM match_attempts ma
            JOIN persons p ON ma.target_id = p.id
            WHERE ma.player_id = %s
            ORDER BY ma.attempted_date DESC
            LIMIT %s
        """, (player_id, limit))
        results = cursor.fetchall()
        return results
    finally:
        conn.close()


def get_success_rate(player_id: int) -> Dict:
    """
    Calculate player's match success rate.

    Args:
        player_id: Player's ID

    Returns:
        Dictionary with success rate statistics
    """
    conn = get_database_connection()
    try:
        cursor = conn.cursor(dictionary=True)
        cursor.execute("""
            SELECT
                COUNT(*) as total_attempts,
                SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful_matches,
                AVG(compatibility_score) as avg_compatibility
            FROM match_attempts
            WHERE player_id = %s
        """, (player_id,))
        result = cursor.fetchone()

        if result['total_attempts'] > 0:
            success_rate = (result['successful_matches'] / result['total_attempts']) * 100
        else:
            success_rate = 0

        return {
            'total_attempts': result['total_attempts'] or 0,
            'successful_matches': result['successful_matches'] or 0,
            'success_rate': round(success_rate, 2),
            'avg_compatibility': round(result['avg_compatibility'] or 0, 2)
        }
    finally:
        conn.close()
