"""Ledgerline — append-only audit records for external submissions and destructive actions."""

from __future__ import annotations

from datetime import datetime, timezone
from typing import List, Optional

from sqlalchemy import func, insert, select

from psyc import db, log
from psyc.models import LedgerEntry, Outcome, TLP


_log = log.get(__name__)


def write(
    case_id: str,
    destination: str,
    payload_hash: str,
    submitter_identity: str,
    tlp: TLP,
    outcome: Outcome,
    response_id: Optional[str] = None,
    detail: Optional[str] = None,
) -> None:
    stmt = insert(db.ledger).values(
        timestamp=datetime.now(timezone.utc).isoformat(),
        case_id=case_id,
        destination=destination,
        payload_hash=payload_hash,
        submitter_identity=submitter_identity,
        tlp=tlp.value,
        response_id=response_id,
        outcome=outcome.value,
        detail=detail,
    )
    with db.engine().begin() as conn:
        conn.execute(stmt)
    _log.info("ledger.write", case_id=case_id, destination=destination, outcome=outcome.value, response_id=response_id)


def _row_to_entry(r) -> LedgerEntry:
    return LedgerEntry(
        id=r.id,
        timestamp=datetime.fromisoformat(r.timestamp),
        case_id=r.case_id,
        destination=r.destination,
        payload_hash=r.payload_hash,
        submitter_identity=r.submitter_identity,
        tlp=TLP(r.tlp),
        response_id=r.response_id,
        outcome=Outcome(r.outcome),
        detail=r.detail,
    )


def list_recent(limit: int = 200) -> List[LedgerEntry]:
    stmt = select(db.ledger).order_by(db.ledger.c.timestamp.desc()).limit(limit)
    with db.engine().connect() as conn:
        rows = conn.execute(stmt).fetchall()
    return [_row_to_entry(r) for r in rows]


def list_by_case(case_id: str, limit: int = 200) -> List[LedgerEntry]:
    stmt = select(db.ledger).where(db.ledger.c.case_id == case_id).order_by(db.ledger.c.timestamp.desc()).limit(limit)
    with db.engine().connect() as conn:
        rows = conn.execute(stmt).fetchall()
    return [_row_to_entry(r) for r in rows]


def count() -> int:
    stmt = select(func.count()).select_from(db.ledger)
    with db.engine().connect() as conn:
        return conn.execute(stmt).scalar_one()
