#!/usr/bin/env python3
"""Repair raw_calls.agentname when customer names were stored as agents.

Heuristics (no Mcube source required):
1. Per agent_callinfo, if one agentname dominates (>= min_dominant calls), fix rare
   singleton names on that line to the dominant agent.
2. Per agent_callinfo, if every agentname appears only once (polluted outbound bucket),
   clear agentname so leaderboard groups by agent_callinfo instead of customers.
"""

from __future__ import annotations

import argparse
import os
import sys

import pymysql
from dotenv import load_dotenv
from pymysql.cursors import DictCursor

load_dotenv()


def _db_config():
    return {
        "host": os.getenv("DB_HOST", "127.0.0.1"),
        "port": int(os.getenv("DB_PORT", "3306")),
        "user": os.getenv("DB_USER", "admin"),
        "password": os.getenv("DB_PASSWORD", ""),
        "database": os.getenv("DB_NAME", "voicebot_cluster"),
        "charset": "utf8mb4",
        "cursorclass": DictCursor,
    }


def _table_exists(cursor, name: str) -> bool:
    cursor.execute("SHOW TABLES LIKE %s", (name,))
    return cursor.fetchone() is not None


def repair_bid(cursor, bid: str, *, min_dominant: int, dry_run: bool) -> dict:
    raw_table = f"{bid}_raw_calls"
    if not _table_exists(cursor, raw_table):
        return {"bid": bid, "skipped": True, "reason": "no raw_calls table"}

    cursor.execute(
        f"""
        SELECT callid, agentname, agent_callinfo, direction
        FROM `{raw_table}`
        WHERE agent_callinfo IS NOT NULL AND TRIM(agent_callinfo) != ''
        """
    )
    rows = cursor.fetchall() or []
    if not rows:
        return {"bid": bid, "skipped": True, "reason": "no rows with agent_callinfo"}

    by_line: dict[str, list[dict]] = {}
    global_name_counts: dict[str, int] = {}
    for row in rows:
        line = str(row.get("agent_callinfo") or "").strip()
        name = str(row.get("agentname") or "").strip()
        by_line.setdefault(line, []).append(row)
        if name:
            global_name_counts[name] = global_name_counts.get(name, 0) + 1

    fixes_dominant = 0
    fixes_clear = 0

    for line, line_rows in by_line.items():
        name_counts: dict[str, int] = {}
        for row in line_rows:
            name = str(row.get("agentname") or "").strip()
            if name:
                name_counts[name] = name_counts.get(name, 0) + 1

        if not name_counts:
            continue

        dominant_name, dominant_count = max(name_counts.items(), key=lambda item: item[1])
        max_per_name = max(name_counts.values())

        if max_per_name == 1 and len(name_counts) > 1:
            # Polluted line: each row has a unique "agent" (usually customer names).
            for row in line_rows:
                name = str(row.get("agentname") or "").strip()
                if not name:
                    continue
                fixes_clear += 1
                if dry_run:
                    print(
                        f"[clear] {bid} callid={row['callid']} "
                        f"agentname={name!r} -> '' (line={line})"
                    )
                else:
                    cursor.execute(
                        f"UPDATE `{raw_table}` SET agentname = '' WHERE callid = %s",
                        (row["callid"],),
                    )
            continue

        if dominant_count < min_dominant:
            continue

        for row in line_rows:
            name = str(row.get("agentname") or "").strip()
            if not name or name == dominant_name:
                continue
            if global_name_counts.get(name, 0) > 1:
                continue
            fixes_dominant += 1
            if dry_run:
                print(
                    f"[dominant] {bid} callid={row['callid']} "
                    f"agentname={name!r} -> {dominant_name!r} (line={line})"
                )
            else:
                cursor.execute(
                    f"UPDATE `{raw_table}` SET agentname = %s WHERE callid = %s",
                    (dominant_name, row["callid"]),
                )

    return {
        "bid": bid,
        "skipped": False,
        "fixes_dominant": fixes_dominant,
        "fixes_clear": fixes_clear,
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="Repair customer names stored in agentname.")
    parser.add_argument("--bid", action="append", help="Business ID (repeatable)")
    parser.add_argument("--all-enabled", action="store_true", help="All enabled STT pipeline BIDs")
    parser.add_argument("--min-dominant", type=int, default=2, help="Min calls to trust dominant name")
    parser.add_argument("--dry-run", action="store_true")
    args = parser.parse_args()

    bids: list[str] = []
    if args.bid:
        bids.extend(str(b).strip() for b in args.bid if str(b).strip())
    elif args.all_enabled:
        conn = pymysql.connect(**_db_config())
        try:
            cur = conn.cursor()
            cur.execute(
                "SELECT bid FROM stt_pipeline_bid_config WHERE enabled = 1 ORDER BY bid"
            )
            bids = [str(r["bid"]) for r in (cur.fetchall() or []) if r.get("bid")]
        finally:
            conn.close()
    else:
        parser.error("Provide --bid or --all-enabled")

    if not bids:
        print("No BIDs to process.")
        return 1

    conn = pymysql.connect(**_db_config())
    try:
        cur = conn.cursor()
        totals = {"fixes_dominant": 0, "fixes_clear": 0}
        for bid in bids:
            result = repair_bid(cur, bid, min_dominant=args.min_dominant, dry_run=args.dry_run)
            if result.get("skipped"):
                print(f"BID {bid}: skipped ({result.get('reason')})")
                continue
            print(
                f"BID {bid}: dominant fixes={result['fixes_dominant']}, "
                f"cleared={result['fixes_clear']}"
            )
            totals["fixes_dominant"] += result["fixes_dominant"]
            totals["fixes_clear"] += result["fixes_clear"]
        if not args.dry_run:
            conn.commit()
        print(
            f"Done. dominant={totals['fixes_dominant']}, cleared={totals['fixes_clear']}"
            + (" (dry-run)" if args.dry_run else "")
        )
        return 0
    finally:
        conn.close()


if __name__ == "__main__":
    sys.exit(main() or 0)
