from __future__ import annotations

import os
import sqlite3
import time
from typing import List, Optional, Tuple

from tools.receipts.signing import sign_receipt
from .merkle import compute_merkle_root, generate_inclusion_proof, verify_merkle_inclusion


class AnchorService:
    """Simple SQLite-backed Merkle Anchor service used for testing and local development.

    - Stores anchors and leaf list per anchor_id
    - Signs anchor records using the lightweight sign_receipt shim
    """

    def __init__(self, db_path: Optional[str] = None) -> None:
        self.db_path = db_path or os.getenv("LOOM_ANCHOR_DB", ":memory:")
        self._init_db()

    def _init_db(self) -> None:
        self.conn = sqlite3.connect(self.db_path)
        self.conn.execute(
            """
            CREATE TABLE IF NOT EXISTS anchors (
                anchor_id TEXT PRIMARY KEY,
                merkle_root TEXT NOT NULL,
                created_ts REAL NOT NULL,
                signature TEXT,
                signer_id TEXT,
                leaves_count INTEGER NOT NULL,
                signature_input TEXT,
                content_digest TEXT
            )
            """
        )
        self.conn.execute(
            """
            CREATE TABLE IF NOT EXISTS anchor_leaves (
                anchor_id TEXT,
                idx INTEGER,
                leaf TEXT,
                PRIMARY KEY (anchor_id, idx)
            )
            """
        )
        self.conn.commit()

    def close(self) -> None:
        try:
            self.conn.close()
        except Exception:
            pass

    def add_anchor(self, leaves: List[str], signer_id: Optional[str] = None) -> dict:
        root = compute_merkle_root(leaves)
        # Deterministic anchor id derived from the merkle root so repeated
        # submissions of the same leaf set are idempotent and won't race.
        anchor_id = f"anchor_{root}"
        created_ts = time.time()

        payload = {"anchor_id": anchor_id, "merkle_root": root, "created_ts": created_ts, "count": len(leaves)}
        signed = sign_receipt(payload)

        # If anchor already exists for the same root, return it (idempotent)
        cur = self.conn.cursor()
        cur.execute("SELECT anchor_id, merkle_root, created_ts, signature, signer_id, leaves_count, signature_input, content_digest FROM anchors WHERE merkle_root = ?", (root,))
        existing = cur.fetchone()
        if existing:
            return {
                "anchor_id": existing[0],
                "merkle_root": existing[1],
                "created_ts": existing[2],
                "signature": existing[3],
                "signer_id": existing[4],
                "leaves_count": existing[5],
                "signature_input": existing[6],
                "content_digest": existing[7],
            }

        # store anchor
        cur = self.conn.cursor()
        cur.execute(
            "INSERT INTO anchors (anchor_id, merkle_root, created_ts, signature, signer_id, leaves_count, signature_input, content_digest) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
            (
                anchor_id,
                root,
                created_ts,
                signed.get("signature"),
                signer_id or "local-test-signer",
                len(leaves),
                signed.get("signature_input"),
                signed.get("content_digest"),
            ),
        )
        # store leaves
        for idx, leaf in enumerate(leaves):
            cur.execute("INSERT INTO anchor_leaves (anchor_id, idx, leaf) VALUES (?, ?, ?)", (anchor_id, idx, leaf))

        self.conn.commit()

        return {
            "anchor_id": anchor_id,
            "merkle_root": root,
            "created_ts": created_ts,
            "signature": signed.get("signature"),
            "signer_id": signer_id,
            "signature_input": signed.get("signature_input"),
            "content_digest": signed.get("content_digest"),
        }

    def get_anchor(self, anchor_id: str) -> Optional[dict]:
        cur = self.conn.cursor()
        cur.execute("SELECT anchor_id, merkle_root, created_ts, signature, signer_id, leaves_count, signature_input, content_digest FROM anchors WHERE anchor_id = ?", (anchor_id,))
        row = cur.fetchone()
        if not row:
            return None
        return {
            "anchor_id": row[0],
            "merkle_root": row[1],
            "created_ts": row[2],
            "signature": row[3],
            "signer_id": row[4],
            "leaves_count": row[5],
            "signature_input": row[6],
            "content_digest": row[7],
        }

    def get_leaves(self, anchor_id: str) -> List[str]:
        cur = self.conn.cursor()
        cur.execute("SELECT idx, leaf FROM anchor_leaves WHERE anchor_id = ? ORDER BY idx ASC", (anchor_id,))
        rows = cur.fetchall()
        return [r[1] for r in rows]

    def get_proof(self, anchor_id: str, idx: int) -> Optional[List[str]]:
        leaves = self.get_leaves(anchor_id)
        if not leaves:
            return None
        if idx < 0 or idx >= len(leaves):
            return None
        return generate_inclusion_proof(leaves, idx)


__all__ = [
    "compute_merkle_root",
    "generate_inclusion_proof",
    "verify_merkle_inclusion",
    "AnchorService",
]
