"""Local duplicate-safe reporting effect, not a ledger or distributed EOS."""
from pathlib import Path
from datetime import datetime
import hashlib
import json
import sqlite3
from jsonschema import Draft202012Validator, FormatChecker

ROOT = Path(__file__).resolve().parent
VALIDATOR = Draft202012Validator(
 json.loads((ROOT/"schemas/event.schema.json").read_text(encoding="utf-8")),
 format_checker=FormatChecker()
)

class PayloadConflict(ValueError):
    pass

def canonical(event):
    VALIDATOR.validate(event)
    if type(event["amount_minor"]) is not int:raise ValueError("money must decode as an integer, never float")
    stamp=datetime.fromisoformat(event["occurred_at"].replace("Z","+00:00"))
    if stamp.tzinfo is None:raise ValueError("event timestamp requires timezone")
    return json.dumps(event,sort_keys=True,separators=(",",":"),allow_nan=False).encode()

def open_projection(path):
    con=sqlite3.connect(path,isolation_level=None)
    con.execute("PRAGMA journal_mode=WAL")
    con.execute("PRAGMA synchronous=FULL")
    con.executescript((ROOT/"sql/projection.sql").read_text(encoding="utf-8"))
    return con

def apply_event(con,event):
    fingerprint=hashlib.sha256(canonical(event)).hexdigest()
    con.execute("BEGIN IMMEDIATE")
    try:
        previous=con.execute(
          "SELECT payload_hash FROM inbox WHERE tenant_id=? AND event_id=?",
          (event["tenant_id"],event["event_id"])).fetchone()
        if previous:
            if previous[0]!=fingerprint: raise PayloadConflict("same identity, different payload")
            con.commit()
            return False
        con.execute("INSERT INTO inbox VALUES(?,?,?)",
                    (event["tenant_id"],event["event_id"],fingerprint))
        current=con.execute("SELECT amount_minor FROM totals WHERE tenant_id=? AND currency=?",
                           (event["tenant_id"],event["currency"])).fetchone()
        total=(current[0] if current else 0)+event["amount_minor"]
        if not -(2**63)<=total<2**63: raise ValueError("projection integer overflow")
        con.execute("""INSERT INTO totals VALUES(?,?,?)
          ON CONFLICT(tenant_id,currency) DO UPDATE SET amount_minor=excluded.amount_minor""",
          (event["tenant_id"],event["currency"],total))
        con.commit()
        return True
    except BaseException:
        con.rollback()
        raise
