#!/usr/bin/env python3

import argparse
import csv
import json
from collections import defaultdict
from pathlib import Path


ROOT_SLUG = "hanmac-family"


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Export Baron org-context JSON to CSV files for photo mapping."
    )
    parser.add_argument("--input", required=True, help="Path to org-context JSON file")
    parser.add_argument(
        "--output-dir", required=True, help="Directory where CSV files will be written"
    )
    return parser.parse_args()


def normalize_phone(phone: str) -> str:
    digits = "".join(ch for ch in (phone or "") if ch.isdigit())
    if digits.startswith("82") and len(digits) >= 11:
        digits = "0" + digits[2:]
    return digits


def format_phone(phone: str) -> str:
    digits = normalize_phone(phone)
    if len(digits) == 11:
        return f"{digits[:3]}-{digits[3:7]}-{digits[7:]}"
    if len(digits) == 10:
        return f"{digits[:3]}-{digits[3:6]}-{digits[6:]}"
    return phone or ""


def email_local_part(email: str) -> str:
    if "@" not in (email or ""):
        return ""
    return email.split("@", 1)[0].strip()


def load_json(path: Path) -> dict:
    with path.open("r", encoding="utf-8") as handle:
        return json.load(handle)


def build_tree_indexes(tree: dict) -> tuple[dict, dict, dict]:
    tenant_by_id: dict[str, dict] = {}
    parent_by_id: dict[str, str | None] = {}
    children_by_id: dict[str, list[str]] = defaultdict(list)

    def visit(node: dict, parent_id: str | None) -> None:
        tenant_id = node.get("id", "")
        if not tenant_id:
            return
        tenant_by_id[tenant_id] = node
        parent_by_id[tenant_id] = parent_id
        if parent_id:
            children_by_id[parent_id].append(tenant_id)
        for child in node.get("children", []) or []:
            if isinstance(child, dict):
                visit(child, tenant_id)

    visit(tree, None)
    return tenant_by_id, parent_by_id, children_by_id


def build_flat_tenant_index(tenants: list[dict]) -> dict[str, dict]:
    return {
        tenant.get("id", ""): tenant
        for tenant in tenants
        if isinstance(tenant, dict) and tenant.get("id")
    }


def tenant_path(
    tenant_id: str, tenant_by_id: dict[str, dict], parent_by_id: dict[str, str | None]
) -> list[dict]:
    path: list[dict] = []
    current_id = tenant_id
    while current_id:
        node = tenant_by_id.get(current_id)
        if node is None:
            break
        path.append(node)
        current_id = parent_by_id.get(current_id) or ""
    path.reverse()
    return path


def resolve_company(path: list[dict], tenant: dict) -> tuple[str, str]:
    if not path:
        return tenant.get("id", ""), tenant.get("name", "")

    if len(path) == 1:
        return path[0].get("id", ""), path[0].get("name", "")

    for node in path[1:]:
        node_type = (node.get("type") or "").upper()
        if node_type in {"COMPANY", "ORGANIZATION"}:
            return node.get("id", ""), node.get("name", "")

    first_child = path[1]
    return first_child.get("id", ""), first_child.get("name", "")


def row_sort_key(row: dict) -> tuple:
    phone_key = row["phone_normalized"] or "99999999999"
    return (
        row["company_name"],
        phone_key,
        row["department_name"],
        row["name"],
        row["email"],
    )


def primary_preference(row: dict) -> tuple:
    return (
        0 if row["is_primary"] == "true" else 1,
        0 if row["phone_normalized"] else 1,
        0 if row["grade"] else 1,
        0 if row["position"] else 1,
        row["company_name"],
        row["department_name"],
        row["email"],
    )


def build_rows(payload: dict) -> tuple[list[dict], list[dict], list[dict]]:
    tree = payload.get("tree") or {}
    tenants = payload.get("tenants") or []
    tree_tenant_by_id, parent_by_id, _children_by_id = build_tree_indexes(tree)
    flat_tenant_by_id = build_flat_tenant_index(tenants)

    for tenant_id, tenant in flat_tenant_by_id.items():
        tree_tenant_by_id.setdefault(tenant_id, tenant)

    membership_rows: list[dict] = []
    for tenant in tenants:
        if not isinstance(tenant, dict):
            continue
        tenant_id = tenant.get("id", "")
        tenant_name = tenant.get("name", "")
        path = tenant_path(tenant_id, tree_tenant_by_id, parent_by_id)
        company_tenant_id, company_name = resolve_company(path, tenant)
        path_names = " > ".join(
            node.get("name", "")
            for node in path
            if node.get("name") and node.get("slug") != ROOT_SLUG
        )

        for member in tenant.get("members", []) or []:
            if not isinstance(member, dict):
                continue
            raw_phone = (member.get("phone") or member.get("phoneNumber") or "").strip()
            row = {
                "company_tenant_id": company_tenant_id,
                "company_name": company_name,
                "department_tenant_id": tenant_id,
                "department_name": tenant_name,
                "department_path": path_names,
                "email": (member.get("email") or "").strip(),
                "email_id": email_local_part(member.get("email") or ""),
                "phone_raw": raw_phone,
                "phone_normalized": normalize_phone(raw_phone),
                "phone_display": format_phone(raw_phone),
                "name": (member.get("name") or "").strip(),
                "grade": (member.get("grade") or "").strip(),
                "position": (member.get("position") or "").strip(),
                "member_department": (member.get("department") or "").strip(),
                "is_primary": "true" if member.get("isPrimary") else "false",
                "member_id": (member.get("id") or "").strip(),
            }
            membership_rows.append(row)

    membership_rows.sort(key=row_sort_key)

    primary_rows = [row for row in membership_rows if row["is_primary"] == "true"]

    phone_index: dict[str, list[dict]] = defaultdict(list)
    for row in membership_rows:
        if row["phone_normalized"]:
            phone_index[row["phone_normalized"]].append(row)

    deduped_rows: list[dict] = []
    for phone in sorted(phone_index):
        best = sorted(phone_index[phone], key=primary_preference)[0]
        duplicate_count = len(phone_index[phone])
        selected = dict(best)
        selected["duplicate_row_count_for_phone"] = str(duplicate_count)
        deduped_rows.append(selected)

    deduped_rows.sort(key=row_sort_key)
    return membership_rows, primary_rows, deduped_rows


def write_csv(path: Path, rows: list[dict], fieldnames: list[str]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("w", encoding="utf-8-sig", newline="") as handle:
        writer = csv.DictWriter(handle, fieldnames=fieldnames)
        writer.writeheader()
        for row in rows:
            writer.writerow({field: row.get(field, "") for field in fieldnames})


def write_summary(path: Path, membership_rows: list[dict], primary_rows: list[dict], deduped_rows: list[dict]) -> None:
    company_counts: dict[str, int] = defaultdict(int)
    for row in deduped_rows:
        company_counts[row["company_name"]] += 1

    lines = [
        "Baron org-context CSV export summary",
        f"membership_rows={len(membership_rows)}",
        f"primary_rows={len(primary_rows)}",
        f"deduped_phone_rows={len(deduped_rows)}",
        "company_counts:",
    ]
    for company_name in sorted(company_counts):
        lines.append(f"- {company_name}: {company_counts[company_name]}")
    path.write_text("\n".join(lines) + "\n", encoding="utf-8")


def main() -> None:
    args = parse_args()
    payload = load_json(Path(args.input))
    membership_rows, primary_rows, deduped_rows = build_rows(payload)

    output_dir = Path(args.output_dir)
    fieldnames = [
        "company_tenant_id",
        "company_name",
        "department_tenant_id",
        "department_name",
        "department_path",
        "email",
        "email_id",
        "phone_raw",
        "phone_normalized",
        "phone_display",
        "name",
        "grade",
        "position",
        "member_department",
        "is_primary",
        "member_id",
    ]
    deduped_fieldnames = fieldnames + ["duplicate_row_count_for_phone"]

    write_csv(output_dir / "baron_org_context_membership_rows.csv", membership_rows, fieldnames)
    write_csv(output_dir / "baron_org_context_primary_rows.csv", primary_rows, fieldnames)
    write_csv(output_dir / "baron_org_context_phone_mapping.csv", deduped_rows, deduped_fieldnames)
    write_summary(
        output_dir / "baron_org_context_export_summary.txt",
        membership_rows,
        primary_rows,
        deduped_rows,
    )


if __name__ == "__main__":
    main()
