"""
AI-powered bio generation for dating profiles.

Uses OpenAI to generate natural, engaging dating profile bios based on
character attributes like personality, interests, occupation, and age.
"""

import os
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
from openai import OpenAI
from config import config


# Lazy initialization for OpenAI client
_client = None


def get_openai_client():
    """
    Get or initialize the OpenAI client lazily.

    Returns:
        OpenAI: Initialized OpenAI client

    Raises:
        Exception: If API key is not configured
    """
    global _client
    if _client is None:
        if not hasattr(config, 'OPENAI_API_KEY') or not config.OPENAI_API_KEY:
            raise Exception("OPENAI_API_KEY not configured in config")
        _client = OpenAI(api_key=config.OPENAI_API_KEY)
    return _client


def generate_dating_bio(person: Any) -> str:
    """
    Generate a dating profile bio using OpenAI.

    Args:
        person: Person object or dict with character attributes

    Returns:
        Generated bio string (2-3 sentences)

    Raises:
        Exception: If OpenAI API call fails
    """
    # Handle both person objects and dicts
    if hasattr(person, '__dict__'):
        person_dict = person.__dict__
    else:
        person_dict = person

    # Extract person attributes with defaults
    firstname = person_dict.get('firstname', 'Someone')
    age = person_dict.get('ageYears', person_dict.get('age_years', 18))
    occupation = person_dict.get('occupation', 'Student')
    likes = person_dict.get('likes', [])
    sex = person_dict.get('sex', 'Unknown')

    # Format interests for the prompt
    interests_str = ', '.join(likes[:3]) if likes else 'reading, music, outdoor activities'

    # Construct the prompt
    prompt = f"""Write a natural, engaging dating profile bio (2-3 sentences) for:
    Name: {firstname}, Age: {age}, Sex: {sex}
    Occupation: {occupation}
    Interests: {interests_str}

    Make it conversational, authentic, and appealing. Write in first person.
    Do not include emojis. Keep it under 150 characters."""

    try:
        # Get OpenAI client (lazy initialization)
        client = get_openai_client()

        # Call OpenAI API with new client-based API
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "You are a creative writer helping people create authentic dating profiles."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=100,
            temperature=0.8
        )

        bio = response.choices[0].message.content.strip()

        # Remove quotes if OpenAI wrapped the response
        if bio.startswith('"') and bio.endswith('"'):
            bio = bio[1:-1]
        if bio.startswith("'") and bio.endswith("'"):
            bio = bio[1:-1]

        return bio

    except Exception as e:
        print(f"Error generating bio with OpenAI: {e}")
        # Return a simple fallback bio
        return f"I'm {firstname}, a {age}-year-old {occupation.lower()} who enjoys {interests_str}. Looking to meet new people!"


def save_bio_to_database(person_id: int, bio: str, db_connection) -> None:
    """
    Save generated bio to database.

    Args:
        person_id: Person's database ID
        bio: Generated bio text
        db_connection: MySQL database connection
    """
    cursor = db_connection.cursor()
    query = """
        UPDATE persons
        SET bio = %s, last_bio_update = NOW()
        WHERE id = %s
    """
    cursor.execute(query, (bio, person_id))
    db_connection.commit()
    cursor.close()


def get_or_generate_bio(person_id: int, db_connection=None, force_regenerate: bool = False) -> str:
    """
    Get existing bio or generate new one if needed.

    Bio is cached for 30 days. Will regenerate if:
    - No bio exists
    - Bio is older than 30 days
    - force_regenerate is True

    Args:
        person_id: Person's database ID
        db_connection: MySQL database connection (optional, for dependency injection)
        force_regenerate: Force regeneration even if bio exists

    Returns:
        Bio string
    """
    # Use provided connection or get one locally to avoid circular imports
    if db_connection is None:
        from functions import get_database_connection
        db_connection = get_database_connection()
        should_close_conn = True
    else:
        should_close_conn = False

    try:
        # Fetch person data from database
        cursor = db_connection.cursor(dictionary=True)
        query = "SELECT * FROM persons WHERE id = %s"
        cursor.execute(query, (person_id,))
        person = cursor.fetchone()
        cursor.close()

        if not person:
            raise ValueError(f"Person with id {person_id} not found")

        # Check if we need to generate a new bio
        needs_generation = (
            force_regenerate or
            not person.get('bio') or
            not person.get('last_bio_update') or
            datetime.now() - person['last_bio_update'] > timedelta(days=30)
        )

        if needs_generation:
            # Generate new bio
            bio = generate_dating_bio(person)
            save_bio_to_database(person_id, bio, db_connection)
            return bio
        else:
            # Return existing bio
            return person['bio']
    finally:
        # Close connection only if we created it locally
        if should_close_conn and db_connection:
            db_connection.close()


def regenerate_bio_on_life_change(person_id: int, db_connection=None, event_type: str = None) -> Optional[str]:
    """
    Regenerate bio when major life events occur.

    Triggers regeneration for events like:
    - Job change
    - Graduation
    - Major achievement
    - Relationship status change

    Args:
        person_id: Person's database ID
        db_connection: MySQL database connection (optional, for dependency injection)
        event_type: Type of life event that occurred

    Returns:
        New bio if regenerated, None if event doesn't trigger regeneration
    """
    regeneration_triggers = [
        'job_change',
        'graduation',
        'promotion',
        'breakup',
        'marriage',
        'major_achievement'
    ]

    if event_type in regeneration_triggers:
        return get_or_generate_bio(person_id, db_connection, force_regenerate=True)

    return None


def batch_generate_bios(person_ids: list, db_connection=None, max_api_calls: int = 10) -> Dict[int, str]:
    """
    Generate bios for multiple people (with rate limiting).

    Args:
        person_ids: List of person IDs
        db_connection: MySQL database connection (optional, for dependency injection)
        max_api_calls: Maximum number of OpenAI API calls to make

    Returns:
        Dictionary mapping person_id to bio
    """
    # Use provided connection or get one locally to avoid circular imports
    if db_connection is None:
        from functions import get_database_connection
        db_connection = get_database_connection()
        should_close_conn = True
    else:
        should_close_conn = False

    try:
        results = {}
        api_calls = 0

        for person_id in person_ids:
            if api_calls >= max_api_calls:
                print(f"Reached max API calls limit ({max_api_calls})")
                break

            try:
                bio = get_or_generate_bio(person_id, db_connection)
                results[person_id] = bio

                # Increment counter only if we actually called the API
                cursor = db_connection.cursor(dictionary=True)
                cursor.execute("SELECT last_bio_update FROM persons WHERE id = %s", (person_id,))
                person = cursor.fetchone()
                cursor.close()

                # If bio was just updated, we made an API call
                if person and person['last_bio_update']:
                    time_since_update = datetime.now() - person['last_bio_update']
                    if time_since_update.total_seconds() < 5:  # Updated within last 5 seconds
                        api_calls += 1

            except Exception as e:
                print(f"Error generating bio for person {person_id}: {e}")
                results[person_id] = None

        return results
    finally:
        # Close connection only if we created it locally
        if should_close_conn and db_connection:
            db_connection.close()
