from fastapi import APIRouter, Depends, HTTPException, Query
from typing import Any, Dict, List, Optional
import hashlib
import json
import logging
from datetime import datetime
from ...auth_core import require_admin
from ...services.domain_family import get_registry

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v2/admin", tags=["admin"])


def _registry_digest(reg) -> str:
    """Stable hash of the current alias map (order-independent)"""
    items = sorted(reg.alias_to_family.items())
    blob = json.dumps(items, separators=(",", ":"), ensure_ascii=True)
    return hashlib.sha1(blob.encode("utf-8")).hexdigest()[:12]


def _get_top_families(reg, limit: int = 10) -> list:
    """Get top N families by alias count"""
    family_counts = {}
    for domain, family in reg.alias_to_family.items():
        family_counts[family] = family_counts.get(family, 0) + 1
    return sorted(family_counts.items(), key=lambda x: x[1], reverse=True)[:limit]


def _build_family_to_domains(reg) -> Dict[str, List[str]]:
    family_to_domains: Dict[str, List[str]] = {}
    for domain, family in reg.alias_to_family.items():
        family_to_domains.setdefault(family, []).append(domain)
    for family_id in family_to_domains:
        family_to_domains[family_id].sort()
    return family_to_domains


def _get_family_parent_domain(
    reg, family_id: str, domains: List[str]
) -> Optional[str]:
    parent = None
    if hasattr(reg, "family_parent_domain"):
        parent = reg.family_parent_domain.get(family_id)
    if not parent and domains:
        parent = domains[0]
    return parent


def _get_family_display_name(reg, family_id: str) -> Optional[str]:
    name = None
    if hasattr(reg, "family_display_name"):
        name = reg.family_display_name.get(family_id)
    if not name:
        display_names = getattr(reg, "display_names", None)
        if display_names and display_names.get(family_id):
            name = sorted(display_names[family_id], key=lambda x: x.lower())[0]
    if not name:
        historical_names = getattr(reg, "historical_names", None)
        if historical_names and historical_names.get(family_id):
            name = sorted(historical_names[family_id], key=lambda x: x.lower())[0]
    return name


def _get_company_names(reg, family_id: str) -> List[str]:
    names: List[str] = []
    for attr in ("display_names", "historical_names"):
        mapping = getattr(reg, attr, None)
        if mapping and mapping.get(family_id):
            names.extend(list(mapping[family_id]))
    if not names:
        return []
    seen = set()
    unique = []
    for name in sorted(names, key=lambda x: x.lower()):
        if name in seen:
            continue
        seen.add(name)
        unique.append(name)
    return unique


@router.get("/domain-families")
async def get_domain_families(
    summary: bool = Query(True, description="Return summary only (default true)"),
    account: Any = Depends(require_admin),
) -> Dict[str, Any]:
    """
    Get current domain families configuration.

    Use ?summary=true to get only version and counts without full mappings.
    """
    reg = get_registry()
    version = _registry_digest(reg)

    if summary:
        # Summary mode - no full alias map
        return {
            "version": version,
            "count": len(reg.alias_to_family),
            "family_count": len(set(reg.alias_to_family.values())),
            "top_families": [
                {"family": fam, "aliases": cnt}
                for fam, cnt in _get_top_families(reg, 10)
            ],
        }
    else:
        # Full mode - include complete alias map
        return {
            "version": version,
            "count": len(reg.alias_to_family),
            "alias_to_family": reg.alias_to_family,
        }


@router.get("/domain-families/summary")
async def get_domain_families_summary(
    account: Any = Depends(require_admin),
) -> Dict[str, Any]:
    """
    Get domain families summary - version, counts, and top families only.
    Lightweight endpoint for dashboards.
    """
    reg = get_registry()
    family_to_domains = _build_family_to_domains(reg)
    families = len(family_to_domains)
    total_domains = len(reg.alias_to_family)

    alias_counts: List[int] = []
    top_families: List[Dict[str, Any]] = []
    named_families = 0
    company_names_total = 0

    for family_id, domains in family_to_domains.items():
        parent_domain = _get_family_parent_domain(reg, family_id, domains) or ""
        alias_domains = [d for d in domains if d != parent_domain]
        alias_count = len(alias_domains)
        alias_counts.append(alias_count)
        display_name = _get_family_display_name(reg, family_id)
        if display_name:
            named_families += 1
        company_names = _get_company_names(reg, family_id)
        company_names_total += len(company_names)
        top_families.append(
            {
                "family_id": family_id,
                "parent_domain": parent_domain,
                "display_name": display_name,
                "alias_count": alias_count,
                "company_count": len(company_names),
            }
        )

    alias_counts_sorted = sorted(alias_counts)
    max_aliases = alias_counts_sorted[-1] if alias_counts_sorted else 0
    avg_aliases = (
        sum(alias_counts_sorted) / families if families and alias_counts_sorted else 0
    )
    if not alias_counts_sorted:
        median_aliases = 0
    elif len(alias_counts_sorted) % 2 == 1:
        median_aliases = alias_counts_sorted[len(alias_counts_sorted) // 2]
    else:
        mid = len(alias_counts_sorted) // 2
        median_aliases = (alias_counts_sorted[mid - 1] + alias_counts_sorted[mid]) / 2

    families_with_aliases = sum(1 for count in alias_counts if count > 0)
    families_without_aliases = max(families - families_with_aliases, 0)
    families_with_display_name = named_families
    families_without_display_name = max(families - named_families, 0)

    top_families_sorted = sorted(
        top_families, key=lambda x: (x["alias_count"], x["company_count"]), reverse=True
    )[:10]

    return {
        "totals": {
            "families": families,
            "primary_domains": families,
            "alias_domains": sum(alias_counts),
            "families_with_aliases": families_with_aliases,
            "named_families": named_families,
            "company_names": company_names_total,
        },
        "alias_stats": {
            "average_aliases": avg_aliases,
            "median_aliases": median_aliases,
            "max_aliases": max_aliases,
        },
        "coverage": {
            "families_with_aliases": families_with_aliases,
            "families_without_aliases": families_without_aliases,
            "families_with_display_name": families_with_display_name,
            "families_without_display_name": families_without_display_name,
        },
        "top_families": top_families_sorted,
        "recent_families": [],
        "unknown_domains": [],
    }


@router.get("/domain-families/search")
async def search_domain_families(
    q: str = Query("", description="Search domain or family"),
    account: Any = Depends(require_admin),
) -> List[Dict[str, Any]]:
    reg = get_registry()
    query = (q or "").strip().lower()
    if not query:
        return []

    family_to_domains = _build_family_to_domains(reg)
    family_meta: Dict[str, Dict[str, Any]] = {}
    for family_id, domains in family_to_domains.items():
        parent_domain = _get_family_parent_domain(reg, family_id, domains) or ""
        display_name = _get_family_display_name(reg, family_id)
        company_count = len(_get_company_names(reg, family_id))
        family_meta[family_id] = {
            "parent_domain": parent_domain,
            "display_name": display_name,
            "company_count": company_count,
        }

    results: List[Dict[str, Any]] = []
    for domain, family_id in reg.alias_to_family.items():
        domain_lower = (domain or "").lower()
        family_lower = (family_id or "").lower()
        if query in domain_lower or query in family_lower:
            meta = family_meta.get(family_id, {})
            parent_domain = meta.get("parent_domain") or domain
            results.append(
                {
                    "family_id": family_id,
                    "parent_domain": parent_domain,
                    "display_name": meta.get("display_name"),
                    "domain": domain,
                    "is_alias": domain != parent_domain,
                    "company_count": meta.get("company_count", 0),
                }
            )

    return results


@router.get("/domain-families/{family_id}")
async def get_domain_family_detail(
    family_id: str,
    account: Any = Depends(require_admin),
) -> Dict[str, Any]:
    reg = get_registry()
    normalized = (family_id or "").strip().lower()
    if not normalized:
        raise HTTPException(status_code=404, detail="Family not found")

    family_domains = [
        domain
        for domain, family in reg.alias_to_family.items()
        if (family or "").lower() == normalized
    ]
    if not family_domains:
        raise HTTPException(status_code=404, detail="Family not found")

    family_domains.sort()
    parent_domain = _get_family_parent_domain(reg, normalized, family_domains) or family_domains[0]
    alias_domains = [d for d in family_domains if d != parent_domain]
    company_names = _get_company_names(reg, normalized)

    return {
        "family_id": normalized,
        "parent_domain": parent_domain,
        "display_name": _get_family_display_name(reg, normalized),
        "alias_domains": alias_domains,
        "company_names": company_names,
        "created_at": None,
    }


@router.post("/reload-domain-families")
async def reload_domain_families(
    account: Any = Depends(require_admin),
) -> Dict[str, Any]:
    """Force reload domain families from config"""
    reg = get_registry()

    # Get version before reload
    version_before = _registry_digest(reg)
    count_before = len(reg.alias_to_family)

    # Perform reload
    reg.refresh(force=True)

    # Get version after reload
    version_after = _registry_digest(reg)
    count_after = len(reg.alias_to_family)

    # Audit log - extract account ID from account object
    account_id = (
        getattr(account, "id", None) if hasattr(account, "id") else str(account)
    )
    logger.info(
        "Domain families reloaded by account_id=%s at %s: version %s->%s, count %d->%d",
        account_id,
        datetime.utcnow().isoformat(),
        version_before,
        version_after,
        count_before,
        count_after,
    )

    return {
        "status": "ok",
        "message": "Domain families reloaded",
        "version_before": version_before,
        "version_after": version_after,
        "reloaded_families": count_after,
        "version": version_after,
    }
