#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""audit_tags_across_accounts.py

Auditoria read-only de etiquetas (tags) en TODAS las cuentas de Bucefalo.

Lo que produce:
  - Por cuenta: lista de tags con su id, nombre y casing original.
  - Etiqueta "revisar": presente/ausente en Marca, sucursales y demos.
  - Etiquetas de formulario: detecta variantes y duplicados case-insensitive.
  - Duplicados case-insensitive globales: tags que solo difieren en mayusculas.
  - Reporte global: tags mas comunes, tags huerfanas, inconsistencias.

Read-only. No crea ni modifica nada en Bucefalo.

Uso:
  python scripts/audit_tags_across_accounts.py
  python scripts/audit_tags_across_accounts.py --json generated/reports/tags_audit.json
"""

import argparse
import csv
import json
import os
import sys
from collections import defaultdict, Counter

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

import requests

TOKENS_CSV = os.path.join(ROOT_DIR, "Bucéfalo - Mesa de control - API Tokens - MP.csv")
BASE_URL = "https://services.leadconnectorhq.com"
BRAND_LOCATION_ID = "GbKkBpCmKu2QmloKFHy3"


def load_accounts():
    out = []
    with open(TOKENS_CSV, encoding="utf-8-sig") as f:
        for row in csv.DictReader(f):
            loc = (row.get("Location_ID") or "").strip()
            tok = (row.get("API_token") or "").strip()
            name = (row.get("Nombre") or "").strip()
            if not loc or not tok:
                continue
            out.append({
                "name": name,
                "location_id": loc,
                "token": tok,
                "is_brand": loc == BRAND_LOCATION_ID,
                "is_demo": "demo" in name.lower(),
            })
    return out


def fetch_tags(token, location_id):
    """GET /locations/{locationId}/tags — devuelve la lista de tags de la cuenta."""
    headers = {
        "Authorization": f"Bearer {token}",
        "Version": "2021-07-28",
        "Accept": "application/json",
    }
    url = f"{BASE_URL}/locations/{location_id}/tags"
    r = requests.get(url, headers=headers, timeout=30)
    if r.status_code != 200:
        return {"error": f"HTTP {r.status_code}: {r.text[:200]}"}
    data = r.json()
    return {"tags": data.get("tags", data) if isinstance(data, dict) else data}


def normalize_name(s):
    return (s or "").strip().lower()


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--json", default=None, help="Ruta a archivo JSON para salida estructurada")
    parser.add_argument("--limit", type=int, default=0, help="Limitar a N cuentas (debug)")
    args = parser.parse_args()

    accounts = load_accounts()
    if args.limit:
        accounts = accounts[:args.limit]

    print(f"Auditando tags en {len(accounts)} cuentas...")
    print("=" * 80)

    per_account = []
    all_tag_names = []  # (account_name, location_id, tag_name, tag_id, is_demo, is_brand)

    for i, acc in enumerate(accounts, 1):
        flag = " [DEMO]" if acc["is_demo"] else (" [MARCA]" if acc["is_brand"] else "")
        print(f"[{i}/{len(accounts)}] {acc['name']}{flag} ({acc['location_id']})...", end=" ", flush=True)
        result = fetch_tags(acc["token"], acc["location_id"])
        if "error" in result:
            print(f"ERROR: {result['error']}")
            per_account.append({**acc, "tags": [], "error": result["error"], "token": "***"})
            continue
        tags = result["tags"] or []
        print(f"{len(tags)} tags")
        per_account.append({**acc, "tags": tags, "error": None, "token": "***"})
        for t in tags:
            all_tag_names.append({
                "account": acc["name"],
                "location_id": acc["location_id"],
                "is_demo": acc["is_demo"],
                "is_brand": acc["is_brand"],
                "tag_name": t.get("name", ""),
                "tag_id": t.get("id", ""),
            })

    print("\n" + "=" * 80)
    print("ANALISIS")
    print("=" * 80)

    # 1) Etiqueta "revisar"
    print("\n--- 1) Etiqueta 'revisar' por cuenta ---")
    revisar_status = []
    for acc in per_account:
        if acc.get("error"):
            revisar_status.append({"account": acc["name"], "status": "error", "detail": acc["error"]})
            continue
        matches = [t for t in acc["tags"] if "revisar" in normalize_name(t.get("name"))]
        revisar_status.append({
            "account": acc["name"],
            "location_id": acc["location_id"],
            "is_brand": acc["is_brand"],
            "is_demo": acc["is_demo"],
            "found": [t.get("name") for t in matches],
        })
    # Print: separados por marca / sucursal / demo
    def _print_group(label, group):
        print(f"\n  {label}:")
        for r in group:
            if r.get("status") == "error":
                print(f"    [ERROR] {r['account']}: {r['detail']}")
                continue
            mark = "OK" if r["found"] else "FALTA"
            names = ", ".join(repr(n) for n in r["found"]) if r["found"] else "(sin tag 'revisar')"
            print(f"    [{mark}] {r['account']}: {names}")

    brand = [r for r in revisar_status if r.get("is_brand")]
    demos = [r for r in revisar_status if r.get("is_demo")]
    sucursales = [r for r in revisar_status if not r.get("is_brand") and not r.get("is_demo")]
    _print_group("MARCA", brand)
    _print_group("DEMOS", demos)
    _print_group("SUCURSALES", sucursales)

    # 2) Etiquetas de formulario
    print("\n--- 2) Etiquetas de formulario (filtro: 'form', 'formulario', 'lead', 'contacto') ---")
    form_pattern_keys = ("form", "lead-form", "contact-form")
    form_tags_by_acc = []
    for acc in per_account:
        if acc.get("error"):
            continue
        forms = [t for t in acc["tags"] if any(k in normalize_name(t.get("name")) for k in form_pattern_keys)]
        if forms:
            form_tags_by_acc.append({
                "account": acc["name"],
                "location_id": acc["location_id"],
                "is_brand": acc["is_brand"],
                "is_demo": acc["is_demo"],
                "form_tags": [{"name": t.get("name"), "id": t.get("id")} for t in forms],
            })
    for entry in form_tags_by_acc:
        flag = " [DEMO]" if entry["is_demo"] else (" [MARCA]" if entry["is_brand"] else "")
        names = ", ".join(repr(t["name"]) for t in entry["form_tags"])
        print(f"  {entry['account']}{flag}: {len(entry['form_tags'])} tag(s) -> {names}")

    # 3) Duplicados case-insensitive POR cuenta
    print("\n--- 3) Duplicados case-insensitive POR cuenta ---")
    intra_dupes = []
    for acc in per_account:
        if acc.get("error"):
            continue
        grouped = defaultdict(list)
        for t in acc["tags"]:
            grouped[normalize_name(t.get("name"))].append(t.get("name"))
        dupes = {k: v for k, v in grouped.items() if len(v) > 1}
        if dupes:
            intra_dupes.append({"account": acc["name"], "location_id": acc["location_id"], "dupes": dupes})
            print(f"  {acc['name']}:")
            for k, names in dupes.items():
                print(f"    '{k}' aparece como: {names}")
    if not intra_dupes:
        print("  (ninguna cuenta tiene tags duplicados intra-cuenta case-insensitive)")

    # 4) Variantes de un mismo tag entre cuentas (foco: tags compartidos)
    print("\n--- 4) Variantes de casing del MISMO tag entre cuentas ---")
    name_variants = defaultdict(set)
    for entry in all_tag_names:
        name_variants[normalize_name(entry["tag_name"])].add(entry["tag_name"])
    cross_variants = {k: sorted(v) for k, v in name_variants.items() if len(v) > 1}
    if cross_variants:
        for k, vs in sorted(cross_variants.items()):
            print(f"  '{k}' tiene {len(vs)} variantes: {vs}")
    else:
        print("  (sin variantes de casing cross-cuenta)")

    # 5) Top 30 tags mas comunes (por cantidad de cuentas que lo tienen)
    print("\n--- 5) Top 30 tags por adopcion (cantidad de cuentas que lo tienen) ---")
    coverage = Counter()
    for k, v in name_variants.items():
        for acc in per_account:
            if acc.get("error"):
                continue
            if any(normalize_name(t.get("name")) == k for t in acc["tags"]):
                coverage[k] += 1
    n_accounts = sum(1 for a in per_account if not a.get("error"))
    for tag_name, cnt in coverage.most_common(30):
        pct = cnt * 100 / max(n_accounts, 1)
        variants = sorted(name_variants[tag_name])
        v_repr = f" (variantes: {variants})" if len(variants) > 1 else ""
        print(f"  {cnt}/{n_accounts} ({pct:.0f}%)  '{tag_name}'{v_repr}")

    # 6) Tags solo en Marca, solo en sucursales, solo en demos
    print("\n--- 6) Coverage por segmento (Marca / Sucursales / Demos) ---")
    by_segment = {"brand": set(), "branch": set(), "demo": set()}
    for entry in all_tag_names:
        seg = "brand" if entry["is_brand"] else ("demo" if entry["is_demo"] else "branch")
        by_segment[seg].add(normalize_name(entry["tag_name"]))
    print(f"  Tags unicos en Marca:     {len(by_segment['brand'])}")
    print(f"  Tags unicos en Sucursales:{len(by_segment['branch'])}")
    print(f"  Tags unicos en Demos:     {len(by_segment['demo'])}")
    only_brand = by_segment["brand"] - by_segment["branch"] - by_segment["demo"]
    only_branches = by_segment["branch"] - by_segment["brand"] - by_segment["demo"]
    print(f"  Solo en Marca (no en sucursales ni demos): {len(only_brand)}")
    if only_brand:
        for t in sorted(only_brand)[:20]:
            print(f"    '{t}'")
        if len(only_brand) > 20:
            print(f"    ... y {len(only_brand)-20} mas")

    # Salida JSON opcional
    if args.json:
        os.makedirs(os.path.dirname(args.json) or ".", exist_ok=True)
        payload = {
            "n_accounts": n_accounts,
            "per_account": [
                {k: v for k, v in acc.items() if k != "token"}
                for acc in per_account
            ],
            "revisar_status": revisar_status,
            "form_tags": form_tags_by_acc,
            "intra_account_dupes": intra_dupes,
            "cross_account_variants": cross_variants,
            "coverage_top": [{"tag": k, "count": c} for k, c in coverage.most_common(50)],
        }
        with open(args.json, "w", encoding="utf-8") as f:
            json.dump(payload, f, ensure_ascii=False, indent=2)
        print(f"\nReporte JSON escrito en: {args.json}")


if __name__ == "__main__":
    main()
