"""
Database layer — MySQL operations connecting directly to CapRover instance.
"""

import json
import mysql.connector
from mysql.connector import pooling
from contextlib import contextmanager

from config import get_settings
from models import Scenario, ScenarioGenerationResult


_pool: pooling.MySQLConnectionPool | None = None


def _get_pool() -> pooling.MySQLConnectionPool:
    global _pool
    if _pool is None:
        s = get_settings()
        _pool = pooling.MySQLConnectionPool(
            pool_name="scenario_pool",
            pool_size=5,
            host=s.MYSQL_HOST,
            port=s.MYSQL_PORT,
            user=s.MYSQL_USER,
            password=s.MYSQL_PASSWORD,
            database=s.MYSQL_DATABASE,
        )
    return _pool


@contextmanager
def get_connection():
    conn = _get_pool().get_connection()
    try:
        yield conn
        conn.commit()
    except Exception:
        conn.rollback()
        raise
    finally:
        conn.close()


def init_db():
    """Create the scenarios table if it doesn't exist."""
    ddl = """
    CREATE TABLE IF NOT EXISTS scenarios (
        id                  VARCHAR(20) PRIMARY KEY,
        title               TEXT NOT NULL,
        short_description   TEXT,
        givens_table        JSON,
        scenario_paragraph  TEXT,
        best_answer         TEXT,
        best_answer_rationale TEXT,
        other_option1       TEXT,
        other_option1_exp   TEXT,
        other_option2       TEXT,
        other_option2_exp   TEXT,
        other_option3       TEXT,
        other_option3_exp   TEXT,
        event_type          VARCHAR(20) DEFAULT 'normal',
        difficulty          VARCHAR(20) DEFAULT 'medium',
        category            VARCHAR(100) DEFAULT 'General',
        risk_level          VARCHAR(20) DEFAULT 'Medium',
        created_at          TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    """
    with get_connection() as conn:
        cursor = conn.cursor()
        cursor.execute(ddl)


def insert_scenario(s: Scenario):
    """Insert one scenario — parameterized, avoiding SQL injection."""
    sql = """
        INSERT INTO scenarios (
            id, title, short_description, givens_table,
            scenario_paragraph, best_answer, best_answer_rationale,
            other_option1, other_option1_exp,
            other_option2, other_option2_exp,
            other_option3, other_option3_exp,
            event_type, difficulty, category, risk_level
        ) VALUES (
            %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
        )
        ON DUPLICATE KEY UPDATE
            title = VALUES(title),
            short_description = VALUES(short_description),
            givens_table = VALUES(givens_table),
            scenario_paragraph = VALUES(scenario_paragraph),
            risk_level = VALUES(risk_level)
    """

    # Pad extra options if Gemini returns less than 3
    others = s.other_answers + [
        type("Obj", (), {"answer": "", "explanation": ""})()
    ] * 3 

    ctx = (s.givens_table.context or "").lower() if s.givens_table else ""
    category = "Financial Crisis" if any(
        kw in ctx for kw in ["crisis", "crash", "covid", "pandemic", "collapse"]
    ) else "General"

    params = (
        s.id,
        s.title,
        s.short_description,
        json.dumps(s.givens_table.model_dump() if s.givens_table else {}),
        s.scenario_paragraph,
        s.best_answer.answer,
        s.best_answer.rationale,
        others[0].answer,
        others[0].explanation,
        others[1].answer,
        others[1].explanation,
        others[2].answer,
        others[2].explanation,
        s.event_type or "normal",
        "medium",
        category,
        s.risk_level
    )

    with get_connection() as conn:
        cursor = conn.cursor()
        cursor.execute(sql, params)


def insert_all_scenarios(result: ScenarioGenerationResult) -> int:
    """Bulk insert all scenarios to CapRover database. Returns count inserted."""
    count = 0
    for s in result.scenarios:
        insert_scenario(s)
        count += 1
    return count


def get_random_scenario() -> dict | None:
    """Pull one random scenario for the Interactive Advisor Bot."""
    sql = """
        SELECT id, title, short_description, givens_table,
               scenario_paragraph, best_answer, best_answer_rationale,
               other_option1, other_option1_exp,
               other_option2, other_option2_exp,
               other_option3, other_option3_exp,
               event_type, difficulty, category, risk_level
        FROM scenarios
        ORDER BY RAND()
        LIMIT 1
    """
    with get_connection() as conn:
        cursor = conn.cursor(dictionary=True)
        cursor.execute(sql)
        row = cursor.fetchone()
    return row
