"""PostgreSQL history store for engine provenance tracking.

This module is intentionally thin: it owns connection, table routing, append
operations, and snapshot reads for the history-first operating model.
"""
from __future__ import annotations

import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Iterable


DOMAIN_TABLES = {
    "market_raw_history": "engine_history.market_raw_history",
    "factor_version_history": "engine_history.factor_version_history",
    "factor_output_history": "engine_history.factor_output_history",
    "decision_result_history": "engine_history.decision_result_history",
    "market_vs_engine_gap_history": "engine_history.market_vs_engine_gap_history",
}


@dataclass(frozen=True)
class HistoryRow:
    domain: str
    payload: dict[str, Any]


def _is_pg_dsn(value: str) -> bool:
    return value.startswith("postgresql://") or value.startswith("postgres://")


def connect(dsn_or_path: str | Path) -> Any:
    value = str(dsn_or_path)
    if _is_pg_dsn(value):
        try:
            import psycopg2
        except ImportError as exc:
            raise ImportError("PostgreSQL DSN requires psycopg2") from exc
        return psycopg2.connect(value)
    raise ValueError("postgresql_history_store_v1 only accepts a PostgreSQL DSN")


def ensure_schema(conn: Any) -> None:
    sql = """
    CREATE SCHEMA IF NOT EXISTS engine_history;
    """
    cur = conn.cursor()
    cur.execute(sql)
    conn.commit()


def append_row(conn: Any, domain: str, payload: dict[str, Any]) -> None:
    table = DOMAIN_TABLES.get(domain)
    if not table:
        raise KeyError(f"unknown domain: {domain}")
    ensure_schema(conn)
    keys = [k for k in payload.keys() if k != "id"]
    cols = ", ".join(keys + ["provenance"])
    placeholders = ", ".join(["%s"] * (len(keys) + 1))
    values = [json.dumps(payload.get(k), ensure_ascii=False, default=str) if isinstance(payload.get(k), (dict, list)) else payload.get(k) for k in keys]
    values.append(json.dumps(payload.get("provenance") or {}, ensure_ascii=False, default=str))
    sql = f"INSERT INTO {table} ({cols}) VALUES ({placeholders})"
    cur = conn.cursor()
    cur.execute(sql, values)
    conn.commit()


def append_rows(conn: Any, rows: Iterable[HistoryRow]) -> None:
    for row in rows:
        append_row(conn, row.domain, row.payload)


def snapshot_table(conn: Any, domain: str, limit: int = 1000) -> list[dict[str, Any]]:
    table = DOMAIN_TABLES.get(domain)
    if not table:
        raise KeyError(f"unknown domain: {domain}")
    cur = conn.cursor()
    cur.execute(f"SELECT * FROM {table} ORDER BY created_at DESC LIMIT %s", (limit,))
    columns = [col[0] for col in cur.description]
    return [dict(zip(columns, row)) for row in cur.fetchall()]

