"""
Afton Dup-Pair JE Stager
========================
Builds a single 70-line Journal Entry that reverses duplicate revenue and
duplicate cash for all 35 dup pairs identified in the topology survey, then
queues it for Jimmie's approval via the QBO Write Queue.

For each pair:
  Dr {target invoice's income account}  $amount   (reverses phantom revenue)
  Cr {dup payment's deposit account}    $amount   (reverses phantom cash)

Source: afton_je_topology_survey.json (must be regenerated first if pairs change).

Defaults to DRY RUN. Pass --apply to actually append to write_queue.json.
"""
from __future__ import annotations

import argparse
import json
import sys
from datetime import datetime
from pathlib import Path

if hasattr(sys.stdout, "reconfigure"):
    sys.stdout.reconfigure(encoding="utf-8", errors="replace")

SCRIPT_DIR = Path(__file__).resolve().parent
QBO_APP_DIR = SCRIPT_DIR.parent.parent / "Atlas" / "app"
QUEUE_DIR = SCRIPT_DIR.parent.parent / "Team" / "Riv" / "j2_qbo_mcp"
sys.path.insert(0, str(QBO_APP_DIR))
sys.path.insert(0, str(QUEUE_DIR))

from queue_backend import append as queue_append  # type: ignore

CLIENT = "afton"
SURVEY_JSON = SCRIPT_DIR / "afton_je_topology_survey.json"
TXN_DATE = "2026-05-22"
DOC_NUMBER = "AFTON-DUP-CLEAN"  # 15 chars, well under 21 limit
ACCT_NAMES = {
    "4": "Undeposited Funds",
    "61": "RBFCU Checking 9015",
    "118": "QuickBooks Payments Sales",
    "132": "Thryv Transactions",
}


def build_je(survey_rows: list[dict]) -> dict:
    lines: list[dict] = []
    dr_total = 0.0
    cr_total = 0.0
    per_pair_audit: list[str] = []

    for r in survey_rows:
        customer = r["customer"]
        target_inv_id = r["target_invoice_id"]
        dup_pmt_id = r["dup_payment_id"]
        amt = float(r["target_invoice_total"])
        income_lines = r["income_lines"]
        if len(income_lines) != 1:
            raise RuntimeError(
                f"Unexpected: {customer} has {len(income_lines)} income lines, expected 1"
            )
        income_acct_ref = income_lines[0]["item_account_ref"]
        deposit_acct_ref = r["dup_payment_deposit_acct"]

        if not income_acct_ref or not deposit_acct_ref:
            raise RuntimeError(f"Missing acct ref for {customer}")

        desc_base = (
            f"Dup cleanup: {customer} | inv {target_inv_id} #{r.get('target_invoice_doc','?')} | "
            f"pmt {dup_pmt_id}"
        )

        # Dr Income (reverses phantom revenue)
        lines.append({
            "Description": f"{desc_base} | Reverse revenue",
            "Amount": amt,
            "PostingType": "Debit",
            "AccountRef": {
                "value": str(income_acct_ref["value"]),
                "name": income_acct_ref["name"],
            },
        })
        dr_total += amt

        # Cr Deposit account (reverses phantom cash)
        lines.append({
            "Description": f"{desc_base} | Reverse cash",
            "Amount": amt,
            "PostingType": "Credit",
            "AccountRef": {
                "value": str(deposit_acct_ref["value"]),
                "name": ACCT_NAMES.get(str(deposit_acct_ref["value"]), deposit_acct_ref.get("name", "?")),
            },
        })
        cr_total += amt

        per_pair_audit.append(
            f"{customer}: ${amt:.2f} Dr {income_acct_ref['name']} / "
            f"Cr {ACCT_NAMES.get(str(deposit_acct_ref['value']), '?')} "
            f"[target_inv={target_inv_id}, dup_pmt={dup_pmt_id}]"
        )

    if abs(dr_total - cr_total) > 0.01:
        raise RuntimeError(f"JE unbalanced: Dr=${dr_total:.2f} Cr=${cr_total:.2f}")

    private_note = (
        f"Afton dup-pair cleanup — reverses duplicate revenue & cash from 35 "
        f"Thryv/QBPay-sync-glitch dup pairs (24 untouched 2024 originals + 11 "
        f"Track A recovery invoices from 2026-05-22). Pairs: $22,063.24 across "
        f"income accts 118 ($9,760) + 132 ($12,303.24); deposit accts 4 "
        f"($21,688.24 UF) + 61 ($375.00 RBFCU - Amy Erwin). "
        f"Per-pair audit:\n" + "\n".join(per_pair_audit)
    )

    payload = {
        "TxnDate": TXN_DATE,
        "Line": lines,
        "Adjustment": True,
        "DocNumber": DOC_NUMBER,
        "PrivateNote": private_note,
    }
    return payload, dr_total


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--apply", action="store_true", help="Append to write_queue.json")
    args = ap.parse_args()

    survey = json.load(open(SURVEY_JSON, encoding="utf-8"))
    rows = survey["rows"]
    print(f"Loaded {len(rows)} pairs from survey")

    payload, total = build_je(rows)
    n_lines = len(payload["Line"])
    print(f"\nBuilt JE: {n_lines} lines, Dr=Cr=${total:,.2f}")
    print(f"  TxnDate:     {payload['TxnDate']}")
    print(f"  DocNumber:   {payload['DocNumber']}  ({len(payload['DocNumber'])} chars)")
    print(f"  Adjustment:  {payload['Adjustment']}")
    print(f"  PrivateNote: {len(payload['PrivateNote'])} chars")

    # Breakdown by acct
    dr_by_acct: dict[str, float] = {}
    cr_by_acct: dict[str, float] = {}
    for ln in payload["Line"]:
        key = f"{ln['AccountRef']['value']} - {ln['AccountRef']['name']}"
        if ln["PostingType"] == "Debit":
            dr_by_acct[key] = dr_by_acct.get(key, 0) + ln["Amount"]
        else:
            cr_by_acct[key] = cr_by_acct.get(key, 0) + ln["Amount"]

    print("\nDr (Income reversals):")
    for k, v in sorted(dr_by_acct.items()):
        print(f"  {k:50s}  ${v:>12,.2f}")
    print("\nCr (Cash reversals):")
    for k, v in sorted(cr_by_acct.items()):
        print(f"  {k:50s}  ${v:>12,.2f}")

    if not args.apply:
        print("\nDRY RUN — pass --apply to actually queue.")
        return

    row_id = queue_append({
        "timestamp": datetime.now().isoformat(timespec="seconds"),
        "client": CLIENT,
        "tool_called": "create_journal_entry",
        "payload_json": json.dumps(payload, default=str),
        "requested_by": "Ledger (afton_je_stage_dup_cleanup.py)",
        "status": "Pending",
        "tier": 1,  # JE tier per tier_config.json
    })
    print(f"\nQUEUED as row {row_id}")
    print("Approval: open the QBO Write Queue Sheet → 'afton' tab → drop Y in Approve col")


if __name__ == "__main__":
    main()
