"""acta-sql: Query Veritas Acta receipt DAGs with SQL."""

from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Any, List, Optional, Union

import duckdb

__version__ = "0.1.0"


def load_receipts(
    path_or_data: Union[str, Path, list[dict[str, Any]]]
) -> list[dict[str, Any]]:
    """Load receipts from a .json file, .jsonl file, or a Python list.

    Args:
        path_or_data: A file path (.json or .jsonl) or a list of receipt dicts.

    Returns:
        A list of receipt dictionaries.
    """
    if isinstance(path_or_data, list):
        return path_or_data

    path = Path(path_or_data)
    text = path.read_text(encoding="utf-8")

    if path.suffix == ".jsonl":
        return [json.loads(line) for line in text.strip().splitlines() if line.strip()]

    data = json.loads(text)
    if isinstance(data, list):
        return data
    # Support a top-level object with a "receipts" array
    if isinstance(data, dict) and "receipts" in data:
        return data["receipts"]
    # Single receipt wrapped in a list
    return [data]


def create_db(
    receipts: list[dict[str, Any]],
    db_path: str = ":memory:",
) -> duckdb.DuckDBPyConnection:
    """Create a DuckDB database with receipts, edges, and payloads tables.

    Args:
        receipts: List of Acta receipt dicts.
        db_path: Path for the DuckDB file, or \":memory:\" for in-memory.

    Returns:
        A DuckDB connection ready for queries.
    """
    conn = duckdb.connect(db_path)

    conn.execute("""
        CREATE TABLE IF NOT EXISTS receipts (
            id              VARCHAR PRIMARY KEY,
            type            VARCHAR,
            tool_name       VARCHAR,
            decision        VARCHAR,
            agent_id        VARCHAR,
            issuer_id       VARCHAR,
            timestamp       VARCHAR,
            policy_hash     VARCHAR,
            signature       VARCHAR,
            raw_json        VARCHAR
        )
    """)

    conn.execute("""
        CREATE TABLE IF NOT EXISTS edges (
            source_id   VARCHAR,
            target_id   VARCHAR,
            relation    VARCHAR
        )
    """)

    conn.execute("""
        CREATE TABLE IF NOT EXISTS payloads (
            receipt_id  VARCHAR,
            key         VARCHAR,
            value       VARCHAR
        )
    """)

    for r in receipts:
        rid = r.get("id", "")
        conn.execute(
            """INSERT OR REPLACE INTO receipts
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
            [
                rid,
                r.get("type"),
                r.get("tool_name"),
                r.get("decision"),
                r.get("agent_id"),
                r.get("issuer_id"),
                str(r.get("timestamp", "")),
                r.get("policy_hash"),
                r.get("signature"),
                json.dumps(r),
            ],
        )

        # Edges from parent_receipts
        for parent in r.get("parent_receipts", []):
            if isinstance(parent, str):
                parent_id, relation = parent, "parent"
            elif isinstance(parent, dict):
                parent_id = parent.get("id", "")
                relation = parent.get("relation", "parent")
            else:
                continue
            conn.execute(
                "INSERT INTO edges VALUES (?, ?, ?)",
                [parent_id, rid, relation],
            )

        # Flatten payload fields
        payload = r.get("payload", {})
        if isinstance(payload, dict):
            for key, value in payload.items():
                conn.execute(
                    "INSERT INTO payloads VALUES (?, ?, ?)",
                    [rid, key, json.dumps(value) if not isinstance(value, str) else value],
                )

    return conn


def query(
    db: duckdb.DuckDBPyConnection,
    sql: str,
) -> list[tuple[Any, ...]]:
    """Execute a SQL query and return all results as a list of tuples.

    Args:
        db: A DuckDB connection (from create_db).
        sql: A SQL query string.

    Returns:
        Query results as a list of tuples.
    """
    return db.execute(sql).fetchall()
