"""
Afton — Reverse 2024 Over-Cleanup (Prior Period Adjustment)
============================================================
Today's JE 27061 ($22K dup cleanup) and JE 27062 ($203K UF plug) both
reversed phantom income for entries spanning 2024-2026. Per the 2025/2026-only
scope locked 2026-05-23, the pre-2025 portion ($114,939) was out of scope.

This JE surgically reverses just the 2024 income reversal portion of today's
work by debiting Retained Earnings (proper prior-period adjustment per GAAP)
and crediting back the Income accounts proportionally to what today's JEs hit.

Effect:
  - 2026 P&L income: +$114,939 (cancels the 2024-related portion of today's reversals)
  - Retained Earnings: -$114,939 (recognizes the prior-period adjustment)
  - UF: UNCHANGED (cleaned state preserved)
  - 2024 P&L: UNCHANGED (we never touch closed period directly)

Net result: 2026 P&L only shows in-scope cleanup (~$110K). 2024 books unchanged.
Equity reflects the prior-period error.

Defaults to DRY RUN. Pass --apply to stage.
"""
from __future__ import annotations

import argparse
import json
import sys
from collections import defaultdict
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))

import qbo_client as qbo  # type: ignore
from queue_backend import append as queue_append  # type: ignore

CLIENT = "afton"
RETAINED_EARNINGS_ACCT_ID = "2"
TXN_DATE = "2026-05-22"
DOC_NUMBER = "AFTON-PPA-2024"  # 14 chars

FORENSICS_JSON = SCRIPT_DIR / "afton_uf_forensics.json"
SURVEY_JSON = SCRIPT_DIR / "afton_je_topology_survey.json"

# JE 27062's actual income account allocations (from the proportional stager output)
JE_27062_ALLOCATIONS = {
    "49": {"name": "Services", "amount": 100659.05},
    "1":  {"name": "Sales", "amount": 92392.75},
    "55": {"name": "Uncategorized Income", "amount": 6232.87},
    "118": {"name": "QuickBooks Payments Sales", "amount": 3766.21},
}
JE_27062_TOTAL = sum(v["amount"] for v in JE_27062_ALLOCATIONS.values())  # $203,050.88


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

    # ── Compute JE 27062's 2024 portion ──────────────────────────────────
    forensics = json.load(open(FORENSICS_JSON, encoding="utf-8"))
    no_method = [r for r in forensics["rows"] if not r.get("payment_method_id")]
    # Replicate the auto-classification used in the stager
    def is_auto(r):
        if r.get("create_time") and r.get("txn_date"):
            try:
                ct = datetime.fromisoformat(r["create_time"].replace("Z", "+00:00")).date()
                td = datetime.fromisoformat(r["txn_date"]).date()
                if (ct - td).days >= 30:
                    return False
            except Exception:
                pass
        return True
    auto = [r for r in no_method if is_auto(r)]
    je27062_2024_amount = sum(r["amount"] for r in auto if (r.get("txn_date") or "")[:4] == "2024")
    print(f"JE 27062 2024 portion: ${je27062_2024_amount:,.2f}")

    # Proportional share of each income acct attributable to 2024 portion
    je27062_2024_share = je27062_2024_amount / JE_27062_TOTAL
    je27062_reversals: dict[str, float] = {}
    for acct_id, v in JE_27062_ALLOCATIONS.items():
        amt = round(v["amount"] * je27062_2024_share, 2)
        je27062_reversals[acct_id] = {"name": v["name"], "amount": amt}

    # ── Compute JE 27061's 2024 portion (per-pair invoice-routed) ────────
    survey = json.load(open(SURVEY_JSON, encoding="utf-8"))
    je27061_reversals: dict[str, dict] = defaultdict(lambda: {"name": "", "amount": 0.0})

    je27061_2024_amount = 0.0
    for r in survey["rows"]:
        # Survey contains all 35 dup pairs. Filter to 2024 untouched.
        if r["track"] != "untouched":
            continue
        if (r.get("target_invoice_date") or "")[:4] != "2024":
            continue
        amt = r["target_invoice_total"]
        je27061_2024_amount += amt
        # Each pair has 1 income line
        income_lines = r["income_lines"]
        if len(income_lines) != 1:
            continue
        iar = income_lines[0]["item_account_ref"]
        acct_id = str(iar["value"])
        je27061_reversals[acct_id]["name"] = iar["name"]
        je27061_reversals[acct_id]["amount"] += amt

    print(f"JE 27061 2024 portion: ${je27061_2024_amount:,.2f}")

    # ── Combine both reversals ───────────────────────────────────────────
    combined: dict[str, dict] = defaultdict(lambda: {"name": "", "amount": 0.0})
    for acct_id, v in je27062_reversals.items():
        combined[acct_id]["name"] = v["name"]
        combined[acct_id]["amount"] += v["amount"]
    for acct_id, v in je27061_reversals.items():
        combined[acct_id]["name"] = v["name"] or combined[acct_id]["name"]
        combined[acct_id]["amount"] += v["amount"]

    total_reversal = sum(v["amount"] for v in combined.values())
    print(f"\nTotal 2024 over-cleanup to reverse: ${total_reversal:,.2f}")
    print("\nProposed Cr Income (reversal) by account:")
    for acct_id, v in sorted(combined.items(), key=lambda x: -x[1]["amount"]):
        print(f"  {acct_id:>4s} {v['name']:<40s} ${v['amount']:>12,.2f}")

    # Rounding correction so Dr = sum of Crs exactly
    total_cr = round(sum(round(v["amount"], 2) for v in combined.values()), 2)
    print(f"\n  Total Cr: ${total_cr:,.2f}")
    print(f"  Dr Retained Earnings: ${total_cr:,.2f}")

    # ── Build JE ──────────────────────────────────────────────────────────
    je_lines = []
    je_lines.append({
        "Description": (
            "Prior Period Adjustment — restore 2026 P&L to in-scope only. "
            "Reverses the 2024-related portion of JE 27061 + JE 27062 income "
            "reversals. Per 2025/2026-only scope locked 2026-05-23."
        ),
        "Amount": total_cr,
        "PostingType": "Debit",
        "AccountRef": {"value": RETAINED_EARNINGS_ACCT_ID, "name": "Retained Earnings"},
    })
    for acct_id, v in sorted(combined.items(), key=lambda x: -x[1]["amount"]):
        amt = round(v["amount"], 2)
        if amt < 0.01:
            continue
        je_lines.append({
            "Description": (
                f"PPA reversal — restore {v['name']} income from 2024-related "
                f"portion of today's UF cleanup"
            ),
            "Amount": amt,
            "PostingType": "Credit",
            "AccountRef": {"value": acct_id, "name": v["name"]},
        })

    dr_total = sum(l["Amount"] for l in je_lines if l["PostingType"] == "Debit")
    cr_total = sum(l["Amount"] for l in je_lines if l["PostingType"] == "Credit")
    diff = round(dr_total - cr_total, 2)
    if abs(diff) > 0.001:
        # Adjust the largest Cr line to absorb rounding
        for l in je_lines:
            if l["PostingType"] == "Credit":
                l["Amount"] = round(l["Amount"] + diff, 2)
                print(f"\nRounding correction of ${diff:.2f} applied to {l['AccountRef']['name']}")
                break
        cr_total = sum(l["Amount"] for l in je_lines if l["PostingType"] == "Credit")
    print(f"\nJE: {len(je_lines)} lines  Dr=${dr_total:,.2f}  Cr=${cr_total:,.2f}")
    if abs(dr_total - cr_total) > 0.01:
        sys.exit(f"JE UNBALANCED: Dr=${dr_total:.2f} Cr=${cr_total:.2f}")

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

    private_note = (
        f"Prior Period Adjustment — restores 2026 P&L to in-scope-only "
        f"by reversing the 2024-portion of JE 27061 + JE 27062 income reversals. "
        f"Per Jimmie 2026-05-23 scope decision: 2025/2026 only. "
        f"This JE: Dr Retained Earnings ${dr_total:,.2f}, Cr Income accts "
        f"(proportional split). Net 2026 P&L income +${dr_total:,.2f}; "
        f"UF unchanged at ~$60K; 2024 books unchanged."
    )[:3900]
    payload = {
        "TxnDate": TXN_DATE,
        "Line": je_lines,
        "Adjustment": True,
        "DocNumber": DOC_NUMBER,
        "PrivateNote": private_note,
    }
    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_2024_overclean_reversal_stager.py)",
        "status": "Pending",
        "tier": 1,
    })
    print(f"\nQUEUED as row {row_id}")


if __name__ == "__main__":
    main()
