"""Receipt submission and retrieval endpoints."""

from __future__ import annotations

import json
import sqlite3

from fastapi import APIRouter, Depends, HTTPException, Query

from ads_foundation.merkle import MerkleProof, Side, verify_proof

from ..auth import require_api_key
from ..db import get_db
from ..models import (
    ProofPathEntry,
    ReceiptDetail,
    ReceiptListResponse,
    ReceiptResponse,
    ReceiptSubmission,
)

router = APIRouter(prefix="/receipts")


def _reconstruct_proof(submission: ReceiptSubmission) -> MerkleProof:
    """Convert API submission to a MerkleProof object."""
    path = [
        (Side[entry.side], bytes.fromhex(entry.sibling_hash))
        for entry in submission.proof
    ]
    return MerkleProof(path=path, root_hash=bytes.fromhex(submission.proof_root))


def _row_to_detail(row: sqlite3.Row) -> ReceiptDetail:
    """Convert a database row to a ReceiptDetail."""
    proof_path = json.loads(row["proof_path"])
    return ReceiptDetail(
        index=row["idx"],
        timestamp=row["timestamp"],
        agent_id=row["agent_id"],
        tool_name=row["tool_name"],
        query_hash=row["query_hash"],
        response_hash=row["response_hash"],
        record_hash=row["record_hash"],
        root_hash=row["root_hash"],
        proof=[ProofPathEntry(**entry) for entry in proof_path],
        proof_root=row["proof_root"],
        received_at=row["received_at"],
    )


@router.post("", response_model=ReceiptResponse, status_code=201)
def submit_receipt(
    body: ReceiptSubmission,
    api_key: dict = Depends(require_api_key),
    conn: sqlite3.Connection = Depends(get_db),
):
    # Verify the Merkle proof server-side
    proof = _reconstruct_proof(body)
    record_hash_bytes = bytes.fromhex(body.record_hash)
    if not verify_proof(record_hash_bytes, proof):
        raise HTTPException(status_code=422, detail="Merkle proof verification failed")

    # Store the receipt
    proof_path_json = json.dumps(
        [{"side": e.side, "sibling_hash": e.sibling_hash} for e in body.proof]
    )
    try:
        conn.execute(
            """INSERT INTO receipts
               (api_key_id, idx, timestamp, agent_id, tool_name,
                query_hash, response_hash, record_hash, root_hash,
                proof_path, proof_root)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
            (
                api_key["id"],
                body.index,
                body.timestamp,
                body.agent_id,
                body.tool_name,
                body.query_hash,
                body.response_hash,
                body.record_hash,
                body.root_hash,
                proof_path_json,
                body.proof_root,
            ),
        )
        conn.commit()
    except sqlite3.IntegrityError:
        raise HTTPException(
            status_code=409,
            detail=f"Receipt at index {body.index} already exists",
        )

    return ReceiptResponse(
        verified=True,
        index=body.index,
        record_hash=body.record_hash,
        root_hash=body.root_hash,
    )


@router.get("", response_model=ReceiptListResponse)
def list_receipts(
    offset: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    agent_id: str | None = Query(None),
    tool_name: str | None = Query(None),
    api_key: dict = Depends(require_api_key),
    conn: sqlite3.Connection = Depends(get_db),
):
    where = "WHERE api_key_id = ?"
    params: list = [api_key["id"]]

    if agent_id:
        where += " AND agent_id = ?"
        params.append(agent_id)
    if tool_name:
        where += " AND tool_name = ?"
        params.append(tool_name)

    total = conn.execute(
        f"SELECT COUNT(*) FROM receipts {where}", params
    ).fetchone()[0]

    rows = conn.execute(
        f"SELECT * FROM receipts {where} ORDER BY idx ASC LIMIT ? OFFSET ?",
        params + [limit, offset],
    ).fetchall()

    return ReceiptListResponse(
        receipts=[_row_to_detail(r) for r in rows],
        total=total,
        offset=offset,
        limit=limit,
    )


@router.get("/{index}", response_model=ReceiptDetail)
def get_receipt(
    index: int,
    api_key: dict = Depends(require_api_key),
    conn: sqlite3.Connection = Depends(get_db),
):
    row = conn.execute(
        "SELECT * FROM receipts WHERE api_key_id = ? AND idx = ?",
        (api_key["id"], index),
    ).fetchone()

    if row is None:
        raise HTTPException(status_code=404, detail=f"Receipt at index {index} not found")

    return _row_to_detail(row)
