#!/usr/bin/env python3
"""Offline synthetic evidence gate; it does not calculate an invoice."""
from dataclasses import dataclass
from typing import Dict, Iterable, List, Tuple

@dataclass(frozen=True)
class Attempt:
    attempt_id: str; job_id: str; account: str; route: str; at: int; upload_body: int; download_body: int

@dataclass(frozen=True)
class Declaration:
    account: str; route: str; start: int; end: int; unit: str; meter_bytes: int
    meter_basis: str; telemetry_basis: str; alignment_evidenced: bool
    complete: bool; declared_adjustment_bytes: int = 0; adjustment_evidenced: bool = False

def reconcile(d: Declaration, attempts: Iterable[Attempt]) -> Tuple[str, str]:
    """Time is half-open [start,end); retry rows remain visible by attempt_id."""
    if (not d.account.strip() or not d.route.strip() or type(d.start) is not int or type(d.end) is not int or type(d.complete) is not bool or not d.complete or d.unit != "bytes" or
            d.meter_basis != "body" or d.telemetry_basis != "body" or type(d.alignment_evidenced) is not bool or not d.alignment_evidenced or
            d.start >= d.end or type(d.meter_bytes) is not int or type(d.declared_adjustment_bytes) is not int or type(d.adjustment_evidenced) is not bool or d.meter_bytes < 0):
        return "HOLD", "missing or invalid declared account, period, unit, or meter"
    seen: Dict[str, Attempt] = {}; rows: List[Attempt] = []; excluded = 0
    for item in attempts:
        if not item.attempt_id.strip() or not item.job_id.strip() or type(item.at) is not int:
            return "HOLD", "blank attempt/job identity or invalid attempt timestamp"
        if item.attempt_id in seen:
            return "HOLD", "duplicate or conflicting attempt_id import: " + item.attempt_id
        seen[item.attempt_id] = item
        if (not item.account.strip() or not item.route.strip() or
                type(item.upload_body) is not int or type(item.download_body) is not int or
                item.upload_body < 0 or item.download_body < 0):
            return "HOLD", "negative client body byte value"
        if item.account != d.account or item.route != d.route:
            return "HOLD", "attempt scope differs from declared account or route"
        if d.start <= item.at < d.end: rows.append(item)
        else: excluded += 1
    if not rows: return "HOLD", "no in-window client telemetry; completeness cannot be established"
    body = sum(x.upload_body + x.download_body for x in rows)
    residual = d.meter_bytes - body
    if d.adjustment_evidenced and residual == d.declared_adjustment_bytes:
        return "RECONCILE", "residual equals independently declared, same-scope adjustment"
    if d.adjustment_evidenced:
        return "INVESTIGATE", "comparable residual differs from declared adjustment"
    if d.declared_adjustment_bytes != 0:
        return "HOLD", "nonzero declared adjustment lacks independent evidence"
    if residual == 0: return "RECONCILE", "declared comparable meter equals client body estimate; excluded=%d" % excluded
    return "HOLD", "residual has no independently declared same-scope explanation"

def checked_cases() -> Dict[str, str]:
    rows = [Attempt("a-1", "job-7", "synthetic-account", "r1", 110, 50, 400), Attempt("a-2", "job-7", "synthetic-account", "r1", 120, 50, 300), Attempt("a-3", "job-8", "synthetic-account", "r1", 150, 50, 400)]
    base = Declaration("synthetic-account", "r1", 100, 200, "bytes", 1250, "body", "body", True, True)
    return {"aligned": reconcile(base, rows)[0],
            "explained_residual": reconcile(Declaration("synthetic-account","r1",100,200,"bytes",1300,"body","body",True,True,50,True), rows)[0],
            "unexplained_residual": reconcile(Declaration("synthetic-account","r1",100,200,"bytes",1300,"body","body",True,True,25,True), rows)[0],
            "ignored_adjustment": reconcile(Declaration("synthetic-account","r1",100,200,"bytes",1250,"body","body",True,True,50,True), rows)[0],
            "duplicate_attempt": reconcile(base, rows + [rows[1]])[0],
            "cross_window_only": reconcile(base, [Attempt("late","job-9","synthetic-account","r1",200,1,1)])[0],
            "wrong_account": reconcile(base, [Attempt("other","job-9","other-account","r1",110,1,1)])[0],
            "empty_account": reconcile(Declaration("","r1",100,200,"bytes",1250,"body","body",True,True), rows)[0],
            "unknown_basis": reconcile(Declaration("synthetic-account","r1",100,200,"bytes",1250,"unknown","body",False,True), rows)[0]}

def main() -> None:
    result = checked_cases()
    assert result == {"aligned":"RECONCILE", "explained_residual":"RECONCILE", "unexplained_residual":"INVESTIGATE", "ignored_adjustment":"INVESTIGATE", "duplicate_attempt":"HOLD", "cross_window_only":"HOLD", "wrong_account":"HOLD", "empty_account":"HOLD", "unknown_basis":"HOLD"}
    assert reconcile(Declaration("synthetic-account","r1",100,200,"bytes",2,"body","body",True,True), [Attempt("start","job-0","synthetic-account","r1",100,1,1)])[0] == "RECONCILE"
    print("aligned=RECONCILE explained_residual=RECONCILE unexplained_residual=INVESTIGATE ignored_adjustment=INVESTIGATE duplicate_attempt=HOLD cross_window_only=HOLD wrong_account=HOLD empty_account=HOLD unknown_basis=HOLD; start_boundary=RECONCILE")
    print("NETWORK_REQUESTS: 0; all accounts, meter values, jobs, attempts and bytes are synthetic")

if __name__ == "__main__": main()
