"""
DuckDB analytics data access layer.

Bridge between the async Quart app and sync DuckDB reads.
All queries run via asyncio.to_thread() against a read-only connection.
"""
import asyncio
import os

import duckdb

# Coffee (Green) commodity code in USDA PSD
COFFEE_COMMODITY_CODE = 711100

# Metrics safe for user-facing queries (prevents SQL injection in dynamic column refs)
ALLOWED_METRICS = frozenset({
    "Production",
    "Imports",
    "Exports",
    "Total_Distribution",
    "Ending_Stocks",
    "Beginning_Stocks",
    "Total_Supply",
    "Domestic_Consumption",
    "Net_Supply",
    "Trade_Balance",
    "Supply_Demand_Balance",
    "Stock_to_Use_Ratio_pct",
    "Production_YoY_pct",
})

_conn: duckdb.DuckDBPyConnection | None = None


def open_analytics_db() -> None:
    """Open read-only DuckDB connection. No-op if the database file does not exist."""
    global _conn
    import pathlib
    db_path = os.getenv("DUCKDB_PATH", "")
    assert db_path, "DUCKDB_PATH environment variable must be set"
    if not pathlib.Path(db_path).exists():
        print(f"[analytics] DuckDB not found at {db_path!r} — analytics disabled")
        return
    _conn = duckdb.connect(db_path, read_only=True)


def close_analytics_db() -> None:
    """Close DuckDB connection."""
    global _conn
    if _conn:
        _conn.close()
        _conn = None


async def fetch_analytics(sql: str, params: list | None = None) -> list[dict]:
    """Run a read-only DuckDB query off the event loop. Returns list of dicts."""
    assert _conn is not None, "Analytics DB not initialized — call open_analytics_db() first"

    def _query():
        result = _conn.execute(sql, params or [])
        columns = [desc[0] for desc in result.description]
        return [dict(zip(columns, row)) for row in result.fetchall()]

    return await asyncio.to_thread(_query)


def _validate_metrics(metrics: list[str]) -> list[str]:
    """Filter metrics to allowed set. Returns validated list."""
    valid = [m for m in metrics if m in ALLOWED_METRICS]
    assert valid, f"No valid metrics in {metrics}. Allowed: {sorted(ALLOWED_METRICS)}"
    return valid


# =============================================================================
# Query Functions
# =============================================================================


async def get_available_commodities() -> list[dict]:
    """Distinct commodity list from serving layer."""
    return await fetch_analytics(
        """
        SELECT DISTINCT commodity_code, commodity_name
        FROM serving.commodity_metrics
        WHERE country_code IS NOT NULL
        ORDER BY commodity_name
        """
    )


async def get_global_time_series(
    commodity_code: int,
    metrics: list[str],
    start_year: int | None = None,
    end_year: int | None = None,
) -> list[dict]:
    """Global supply/demand time series by market_year for a commodity."""
    metrics = _validate_metrics(metrics)
    cols = ", ".join(metrics)

    where_parts = ["country_name = 'Global'", "commodity_code = ?"]
    params: list = [commodity_code]

    if start_year is not None:
        where_parts.append("market_year >= ?")
        params.append(start_year)
    if end_year is not None:
        where_parts.append("market_year <= ?")
        params.append(end_year)

    where_clause = " AND ".join(where_parts)

    return await fetch_analytics(
        f"""
        SELECT market_year, {cols}
        FROM serving.commodity_metrics
        WHERE {where_clause}
        ORDER BY market_year
        """,
        params,
    )


async def get_top_countries(
    commodity_code: int,
    metric: str,
    limit: int = 10,
) -> list[dict]:
    """Country ranking for latest market year by a single metric."""
    metric = _validate_metrics([metric])[0]

    return await fetch_analytics(
        f"""
        WITH latest AS (
            SELECT MAX(market_year) AS max_year
            FROM serving.commodity_metrics
            WHERE commodity_code = ? AND country_code IS NOT NULL
        )
        SELECT country_name, country_code, market_year, {metric}
        FROM serving.commodity_metrics, latest
        WHERE commodity_code = ?
          AND country_code IS NOT NULL
          AND market_year = latest.max_year
        ORDER BY {metric} DESC
        LIMIT ?
        """,
        [commodity_code, commodity_code, limit],
    )


async def get_stock_to_use_trend(commodity_code: int) -> list[dict]:
    """Global stock-to-use ratio over time."""
    return await fetch_analytics(
        """
        SELECT market_year, Stock_to_Use_Ratio_pct
        FROM serving.commodity_metrics
        WHERE commodity_code = ?
          AND country_name = 'Global'
        ORDER BY market_year
        """,
        [commodity_code],
    )


async def get_supply_demand_balance(commodity_code: int) -> list[dict]:
    """Global supply-demand balance trend."""
    return await fetch_analytics(
        """
        SELECT market_year, Production, Total_Distribution, Supply_Demand_Balance
        FROM serving.commodity_metrics
        WHERE commodity_code = ?
          AND country_name = 'Global'
        ORDER BY market_year
        """,
        [commodity_code],
    )


async def get_production_yoy_by_country(
    commodity_code: int,
    limit: int = 15,
) -> list[dict]:
    """Latest YoY production changes by country."""
    return await fetch_analytics(
        """
        WITH latest AS (
            SELECT MAX(market_year) AS max_year
            FROM serving.commodity_metrics
            WHERE commodity_code = ? AND country_code IS NOT NULL
        )
        SELECT country_name, country_code, market_year,
               Production, Production_YoY_pct
        FROM serving.commodity_metrics, latest
        WHERE commodity_code = ?
          AND country_code IS NOT NULL
          AND market_year = latest.max_year
          AND Production > 0
        ORDER BY ABS(Production_YoY_pct) DESC
        LIMIT ?
        """,
        [commodity_code, commodity_code, limit],
    )


async def get_country_comparison(
    commodity_code: int,
    country_codes: list[str],
    metric: str,
) -> list[dict]:
    """Multi-country time series for a single metric."""
    assert len(country_codes) <= 10, "Maximum 10 countries for comparison"
    metric = _validate_metrics([metric])[0]
    placeholders = ", ".join(["?"] * len(country_codes))

    return await fetch_analytics(
        f"""
        SELECT country_name, country_code, market_year, {metric}
        FROM serving.commodity_metrics
        WHERE commodity_code = ?
          AND country_code IN ({placeholders})
        ORDER BY country_name, market_year
        """,
        [commodity_code, *country_codes],
    )
