# edited by glg
import argparse
import os
import re
import sqlite3
import sys
from collections import Counter, defaultdict
from datetime import datetime, timedelta

PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if PROJECT_ROOT not in sys.path:
    sys.path.insert(0, PROJECT_ROOT)

from pypos.core.utils.config_utils import read_app_settings
from pypos.core.utils.path_utils import get_app_data_dir, get_db_path


LINE_TS_RE = re.compile(r"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \|")
SUCCESS_RE = re.compile(
    r"\[SettlementDirect\] BERHASIL counter=([^ ]+) status=(\d+) idem=([a-f0-9]+)"
)
FAILED_RE = re.compile(
    r"\[SettlementDirect\] GAGAL counter=([^ ]+) status=(\d+) retryable=(\d+) idem=([a-f0-9]*) error=(.*)$"
)
SUCCESS_MSG_RE = re.compile(
    r"\[SettlementDirect\] success response message=(.*?) reason=([^ ]+) status=(\d+)"
)
SKIP_RE = re.compile(r"\[SettlementDirect\] Tidak dikirim \(reason=([^\)]+)\)")
EXPORT_SKIP_RE = re.compile(
    r"\[EXPORT\]\[SETTLEMENT\] Trigger dilewati: settlement_delivery_mode=([a-z_]+)"
)
EXPORT_ACCEPT_DIRECT_ONLY_RE = re.compile(
    r"\[EXPORT\]\[SETTLEMENT\] Trigger diterima \(direct_only\)"
)


def _resolve_log_path():
    cfg = read_app_settings()
    log_dir = str(cfg.get("log_dir") or "logs").strip()
    log_file = str(cfg.get("log_file_name") or "pypos.log").strip()
    return os.path.join(get_app_data_dir(), log_dir, log_file)


def _read_direct_log_summary(hours):
    now = datetime.now()
    cutoff = now - timedelta(hours=max(1, int(hours or 24)))
    log_path = _resolve_log_path()
    summary = Counter()
    status_counter = Counter()
    reason_counter = Counter()
    per_counter_success = defaultdict(int)
    per_counter_failed = defaultdict(int)

    if not os.path.isfile(log_path):
        return {
            "log_path": log_path,
            "found": False,
            "summary": {},
            "status_counter": {},
            "reason_counter": {},
            "duplicate_success_counter": {},
            "duplicate_failed_counter": {},
        }

    with open(log_path, "r", encoding="utf-8", errors="ignore") as handle:
        for line in handle:
            ts_match = LINE_TS_RE.match(line)
            if not ts_match:
                continue
            try:
                line_ts = datetime.strptime(ts_match.group(1), "%Y-%m-%d %H:%M:%S")
            except Exception:
                continue
            if line_ts < cutoff:
                continue

            match_export_skip = EXPORT_SKIP_RE.search(line)
            if match_export_skip:
                skipped_mode = str(match_export_skip.group(1) or "").strip().lower() or "unknown"
                summary[f"export_trigger_skipped_mode:{skipped_mode}"] += 1

            if EXPORT_ACCEPT_DIRECT_ONLY_RE.search(line):
                summary["export_trigger_accepted_direct_only"] += 1

            if "[SettlementDirect]" not in line:
                continue

            match_success = SUCCESS_RE.search(line)
            if match_success:
                counter = str(match_success.group(1) or "").strip()
                status_code = str(match_success.group(2) or "").strip()
                summary["success"] += 1
                if status_code:
                    status_counter[status_code] += 1
                if counter:
                    per_counter_success[counter] += 1
                continue

            match_failed = FAILED_RE.search(line)
            if match_failed:
                counter = str(match_failed.group(1) or "").strip()
                status_code = str(match_failed.group(2) or "").strip()
                error_text = str(match_failed.group(5) or "").strip()
                summary["failed"] += 1
                if status_code:
                    status_counter[status_code] += 1
                if error_text:
                    reason_counter[error_text] += 1
                if counter:
                    per_counter_failed[counter] += 1
                continue

            match_msg = SUCCESS_MSG_RE.search(line)
            if match_msg:
                reason_code = str(match_msg.group(2) or "").strip()
                summary["success_message"] += 1
                if reason_code:
                    reason_counter[f"reason:{reason_code}"] += 1
                continue

            match_skip = SKIP_RE.search(line)
            if match_skip:
                summary["skipped"] += 1
                reason_counter[f"skip:{str(match_skip.group(1) or '').strip()}"] += 1

    duplicate_success = {k: v for k, v in per_counter_success.items() if int(v or 0) > 1}
    duplicate_failed = {k: v for k, v in per_counter_failed.items() if int(v or 0) > 1}
    return {
        "log_path": log_path,
        "found": True,
        "summary": dict(summary),
        "status_counter": dict(status_counter),
        "reason_counter": dict(reason_counter),
        "duplicate_success_counter": duplicate_success,
        "duplicate_failed_counter": duplicate_failed,
    }


def _read_db_summary():
    db_path = get_db_path()
    out = {
        "db_path": db_path,
        "found": os.path.isfile(db_path),
        "settlement_history_count": 0,
        "transaksi_settlement_count": 0,
        "export_settlement_status": [],
        "pending_retry_with_file": 0,
    }
    if not out["found"]:
        return out

    conn = sqlite3.connect(db_path)
    cur = conn.cursor()
    try:
        cur.execute("SELECT COUNT(*) FROM settlement_history")
        out["settlement_history_count"] = int(cur.fetchone()[0] or 0)
    except Exception:
        out["settlement_history_count"] = -1
    try:
        cur.execute("SELECT COUNT(*) FROM transaksi_settlement")
        out["transaksi_settlement_count"] = int(cur.fetchone()[0] or 0)
    except Exception:
        out["transaksi_settlement_count"] = -1
    try:
        cur.execute(
            """
            SELECT table_name, status, COALESCE(upload_status,'PENDING') AS upload_status, COUNT(*)
            FROM export_flux
            WHERE table_name IN ('settlement_history','transaksi_settlement')
            GROUP BY table_name, status, COALESCE(upload_status,'PENDING')
            ORDER BY table_name, status, upload_status
            """
        )
        out["export_settlement_status"] = [tuple(r) for r in (cur.fetchall() or [])]
    except Exception:
        out["export_settlement_status"] = []
    try:
        cur.execute(
            """
            SELECT COUNT(*)
            FROM export_flux
            WHERE table_name IN ('settlement_history','transaksi_settlement')
              AND status='SUCCESS'
              AND COALESCE(file_path,'') <> ''
              AND COALESCE(upload_status,'PENDING') IN ('PENDING','RETRY')
            """
        )
        out["pending_retry_with_file"] = int(cur.fetchone()[0] or 0)
    except Exception:
        out["pending_retry_with_file"] = -1
    finally:
        conn.close()
    return out


def main():
    parser = argparse.ArgumentParser(
        description="Diagnosa kesehatan settlement direct + backlog export settlement."
    )
    parser.add_argument(
        "--hours",
        type=int,
        default=24,
        help="Jumlah jam ke belakang untuk audit log (default: 24).",
    )
    args = parser.parse_args()

    log_summary = _read_direct_log_summary(hours=args.hours)
    db_summary = _read_db_summary()

    print("=== SETTLEMENT DIRECT DIAGNOSIS ===")
    print(f"log_path: {log_summary.get('log_path')}")
    if not log_summary.get("found"):
        print("log_found: False")
    else:
        print(f"log_window_hours: {max(1, int(args.hours or 24))}")
        print(f"log_summary: {log_summary.get('summary')}")
        print(f"log_status_counter: {log_summary.get('status_counter')}")
        print(f"log_reason_counter: {log_summary.get('reason_counter')}")
        print(f"log_duplicate_success_counter: {log_summary.get('duplicate_success_counter')}")
        print(f"log_duplicate_failed_counter: {log_summary.get('duplicate_failed_counter')}")

    print(f"db_path: {db_summary.get('db_path')}")
    print(f"settlement_history_count: {db_summary.get('settlement_history_count')}")
    print(f"transaksi_settlement_count: {db_summary.get('transaksi_settlement_count')}")
    print(f"pending_retry_with_file: {db_summary.get('pending_retry_with_file')}")
    print("export_settlement_status:")
    for row in db_summary.get("export_settlement_status") or []:
        print(f"  - {row}")

    if int(db_summary.get("pending_retry_with_file") or 0) > 0:
        print(
            "[WARN] Masih ada backlog settlement berkas upload di export_flux. "
            "Periksa mode delivery atau retry upload."
        )
    else:
        print("[OK] Tidak ada backlog settlement berkas upload yang pending/retry.")


if __name__ == "__main__":
    main()
