from __future__ import annotations

import hashlib
import json
import os
from pathlib import Path

from jarvis_finance.services.household_import import _norm, _sha
from jarvis_finance.storage.database import connect

DB = Path("/home/agent/jarvis_runtime/finance-system/data/finance.sqlite3")
OUT = Path("/home/agent/jarvis_runtime/finance-system/quarantine/sprint22_mapping_snapshot_batch_preview_private.json")


def file_sha256(path: Path) -> str:
    h = hashlib.sha256()
    with path.open("rb") as handle:
        for block in iter(lambda: handle.read(1024 * 1024), b""):
            h.update(block)
    return h.hexdigest()


before = {"sha256": file_sha256(DB), "size": DB.stat().st_size, "mtime_ns": DB.stat().st_mtime_ns}
conn = connect(str(DB))
accounts = conn.execute(
    """SELECT a.account_id,a.account_name,a.account_type,a.balance_mode,p.name platform,
              b.budget_account_id,m.mapping_id,m.source_type,m.source_reference_hash,m.is_active
         FROM accounts a JOIN platforms p ON p.platform_id=a.platform_id
         LEFT JOIN budget_accounts b ON b.linked_account_id=a.account_id AND b.is_active=1
         LEFT JOIN household_account_source_mappings m ON m.canonical_account_id=a.account_id
        WHERE a.is_active=1 AND (p.name='Raiffeisen' OR a.account_type='cash')
        ORDER BY p.name,a.account_name,a.account_id"""
).fetchall()
raiffeisen_sources = [
    str(row[0] or "")
    for row in conn.execute(
        "SELECT DISTINCT account_source FROM budget_transaction_candidates WHERE source_type='raiffeisen_bank'"
    ).fetchall()
]
items = []
for account in accounts:
    source_matches = []
    if account["source_reference_hash"]:
        source_matches = [
            source for source in raiffeisen_sources if _sha(_norm(source)) == account["source_reference_hash"]
        ]
    snapshots = [
        dict(row)
        for row in conn.execute(
            """SELECT snapshot_id,snapshot_type,balance_date,amount_chf,source,created_at
                 FROM cash_account_snapshots WHERE account_id=?
                ORDER BY balance_date,created_at,snapshot_id""",
            (account["account_id"],),
        ).fetchall()
    ]
    items.append(
        {
            "account_id": account["account_id"],
            "account_name": account["account_name"],
            "account_type": account["account_type"],
            "platform": account["platform"],
            "balance_mode": account["balance_mode"],
            "budget_account_id": account["budget_account_id"],
            "mapping_id": account["mapping_id"],
            "mapping_active": bool(account["is_active"]) if account["mapping_id"] else None,
            "matched_source_count": len(source_matches),
            "snapshots": snapshots,
        }
    )
conn.close()

# The imported private-account source already resolves exclusively to 5632. The
# 5031 mapping has no imported source rows, and all four Sprint-21 snapshots are
# attached to their intended canonical accounts. Therefore no productive
# correction is proposed; the Sprint needs read-model fixes only.
preview = {
    "preview_version": "sprint22_mapping_snapshot_batch_preview_v1",
    "database_before": before,
    "accounts": items,
    "planned_mapping_corrections": [],
    "planned_snapshot_corrections": [],
    "expected_writes": {"mappings": 0, "snapshots": 0, "audits": 0},
    "decision": "no_productive_correction_required",
}
preview["input_fingerprint"] = hashlib.sha256(
    json.dumps(preview, ensure_ascii=True, sort_keys=True, separators=(",", ":")).encode()
).hexdigest()
OUT.write_text(json.dumps(preview, ensure_ascii=False, indent=2, default=str), encoding="utf-8")
os.chmod(OUT, 0o600)
after = {"sha256": file_sha256(DB), "size": DB.stat().st_size, "mtime_ns": DB.stat().st_mtime_ns}
print(
    json.dumps(
        {
            "decision": preview["decision"],
            "expected_writes": preview["expected_writes"],
            "raiffeisen_5632_source_matches": next(
                item["matched_source_count"] for item in items if "5632" in str(item["account_name"])
            ),
            "raiffeisen_5031_source_matches": next(
                item["matched_source_count"] for item in items if "5031" in str(item["account_name"])
            ),
            "sprint21_cash_snapshot_count": sum(
                len(item["snapshots"])
                for item in items
                if item["snapshots"]
                and max(str(row["balance_date"]) for row in item["snapshots"]) >= "2026-08-25"
            ),
            "database_unchanged": before == after,
            "private_preview_mode": "0600",
        },
        ensure_ascii=False,
    )
)
