"""
Database layer — PostgreSQL operations connecting directly to Supabase.
"""

import json
import os
import psycopg2
from psycopg2 import pool
from contextlib import contextmanager

from config import get_settings
from models import Scenario, ScenarioGenerationResult

_pool: pool.SimpleConnectionPool | None = None

def _get_pool() -> pool.SimpleConnectionPool:
    global _pool
    if _pool is None:
        s = get_settings()
        # Fallback to SUPABASE_DB_URL from env or settings
        db_url = os.environ.get("SUPABASE_DB_URL") or s.SUPABASE_DB_URL
        if not db_url:
            raise ValueError("SUPABASE_DB_URL is not set.")
        
        _pool = pool.SimpleConnectionPool(
            1, 10,
            dsn=db_url
        )
    return _pool


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


def init_db():
    """No-op for Supabase as tables are managed via Supabase UI/Migrations."""
    pass


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 CONFLICT (id) DO UPDATE SET
            title = EXCLUDED.title,
            short_description = EXCLUDED.short_description,
            givens_table = EXCLUDED.givens_table,
            scenario_paragraph = EXCLUDED.scenario_paragraph,
            risk_level = EXCLUDED.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:
        with conn.cursor() as cursor:
            cursor.execute(sql, params)


def insert_all_scenarios(result: ScenarioGenerationResult) -> int:
    """Bulk insert all scenarios to Supabase 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 RANDOM()
        LIMIT 1
    """
    import psycopg2.extras
    with get_connection() as conn:
        with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cursor:
            cursor.execute(sql)
            row = cursor.fetchone()
            if row:
                row = dict(row)
    return row
