"""
Admin API for domain family metrics and management.
Provides monitoring, analytics, and controlled updates.
"""

from fastapi import APIRouter, HTTPException, Depends, UploadFile, File, BackgroundTasks
from pydantic import BaseModel
from typing import Dict, List, Optional, Any
from datetime import datetime
import json
import duckdb
import yaml
from pathlib import Path
import shutil
from collections import Counter

from ...auth import require_admin
from ...services.domain_family import get_registry

router = APIRouter(prefix="/api/v2/admin/domain-metrics", tags=["admin", "domains"])

# Metrics storage (in production, use Redis or database)
METRICS = {
    "lookups": Counter(),
    "unknowns": Counter(),
    "ambiguous": Counter(),
    "cache_hits": 0,
    "cache_misses": 0,
    "last_reset": datetime.now(),
}


class DomainMetrics(BaseModel):
    """Domain lookup metrics"""

    coverage_rate: float  # % of domains that resolve
    ambiguity_rate: float  # % with multiple matches
    unknown_rate: float  # % unrecognized
    top_unknowns: List[Dict[str, Any]]
    cache_hit_rate: float
    total_lookups: int
    period_start: datetime
    period_end: datetime


class DomainUpdateRequest(BaseModel):
    """Request to update domain families"""

    mode: str = "safe"  # safe, merge, overwrite
    dry_run: bool = True
    companies: List[Dict[str, Any]]


class VersionInfo(BaseModel):
    """Database version information"""

    version: str
    created_at: datetime
    total_families: int
    total_domains: int
    total_names: int
    file_path: str


def track_lookup(domain: str, result: Optional[str]):
    """Track a domain lookup for metrics"""
    METRICS["lookups"][domain] += 1
    if result is None:
        METRICS["unknowns"][domain] += 1
    # TODO: Track ambiguous lookups when implementing fuzzy matching


@router.get("/metrics", response_model=DomainMetrics)
async def get_domain_metrics(days: int = 7, _: Any = Depends(require_admin)):
    """Get domain lookup metrics for monitoring"""

    total_lookups = sum(METRICS["lookups"].values())
    unknown_lookups = sum(METRICS["unknowns"].values())

    # Calculate rates
    coverage_rate = (
        1.0 - (unknown_lookups / total_lookups) if total_lookups > 0 else 1.0
    )
    unknown_rate = unknown_lookups / total_lookups if total_lookups > 0 else 0.0

    # Get top unknown domains
    top_unknowns = [
        {"domain": domain, "count": count, "frequency": count / total_lookups}
        for domain, count in METRICS["unknowns"].most_common(100)
    ]

    # Cache hit rate
    total_cache_ops = METRICS["cache_hits"] + METRICS["cache_misses"]
    cache_hit_rate = (
        METRICS["cache_hits"] / total_cache_ops if total_cache_ops > 0 else 1.0
    )

    return DomainMetrics(
        coverage_rate=coverage_rate,
        ambiguity_rate=0.0,  # TODO: Implement ambiguity tracking
        unknown_rate=unknown_rate,
        top_unknowns=top_unknowns,
        cache_hit_rate=cache_hit_rate,
        total_lookups=total_lookups,
        period_start=METRICS["last_reset"],
        period_end=datetime.now(),
    )


@router.get("/thresholds-status")
async def get_threshold_status(_: Any = Depends(require_admin)):
    """Check if any thresholds are exceeded"""
    total_lookups = sum(METRICS["lookups"].values())
    unknown_lookups = sum(METRICS["unknowns"].values())
    unknown_rate = unknown_lookups / total_lookups if total_lookups > 0 else 0.0

    # Get most frequent unknown
    top_unknown = METRICS["unknowns"].most_common(1)
    top_unknown_count = top_unknown[0][1] if top_unknown else 0

    alerts = []

    # Check thresholds
    if unknown_rate > 0.10:  # > 10% unknown
        alerts.append(
            {
                "type": "high_unknown_rate",
                "severity": "warning",
                "message": f"Unknown domain rate is {unknown_rate:.1%} (threshold: 10%)",
                "value": unknown_rate,
            }
        )

    if unknown_rate > 0.05:  # > 5% unknown (info level)
        alerts.append(
            {
                "type": "elevated_unknown_rate",
                "severity": "info",
                "message": f"Unknown domain rate is {unknown_rate:.1%} (threshold: 5%)",
                "value": unknown_rate,
            }
        )

    if top_unknown_count > 50:  # Single domain > 50 times
        alerts.append(
            {
                "type": "frequent_unknown",
                "severity": "warning",
                "message": f"Domain '{top_unknown[0][0]}' unrecognized {top_unknown_count} times",
                "domain": top_unknown[0][0],
                "count": top_unknown_count,
            }
        )

    # Check cache performance
    registry = get_registry()
    if hasattr(registry, "_last_load"):
        reload_time = time.time() - registry._last_load
        if reload_time > 0.1:  # > 100ms reload
            alerts.append(
                {
                    "type": "slow_reload",
                    "severity": "warning",
                    "message": f"Cache reload took {reload_time*1000:.1f}ms (threshold: 100ms)",
                    "value": reload_time,
                }
            )

    return {
        "healthy": len([a for a in alerts if a["severity"] == "warning"]) == 0,
        "alerts": alerts,
        "metrics": {
            "unknown_rate": unknown_rate,
            "top_unknown_count": top_unknown_count,
            "total_lookups": total_lookups,
        },
        "recommendation": get_expansion_recommendation(unknown_rate, top_unknown_count),
    }


def get_expansion_recommendation(unknown_rate: float, top_unknown_count: int) -> str:
    """Get recommendation for when to expand the dataset"""
    if unknown_rate > 0.10 or top_unknown_count > 50:
        return "EXPAND_NOW: Thresholds exceeded, consider adding more companies"
    elif unknown_rate > 0.05:
        return "MONITOR: Approaching threshold, prepare expansion data"
    else:
        return "STABLE: No expansion needed"


@router.post("/reset-metrics")
async def reset_metrics(_: Any = Depends(require_admin)):
    """Reset metrics collection"""
    METRICS["lookups"].clear()
    METRICS["unknowns"].clear()
    METRICS["ambiguous"].clear()
    METRICS["cache_hits"] = 0
    METRICS["cache_misses"] = 0
    METRICS["last_reset"] = datetime.now()

    return {"message": "Metrics reset", "reset_at": METRICS["last_reset"]}


@router.get("/versions")
async def get_versions(_: Any = Depends(require_admin)) -> List[VersionInfo]:
    """Get all available database versions"""
    versions = []
    db_dir = Path("config")

    # Find all backup files
    for backup_file in db_dir.glob("foundrygraph.duckdb.backup_*"):
        timestamp_str = backup_file.name.split("backup_")[1]
        try:
            # Parse timestamp
            created = datetime.strptime(timestamp_str, "%Y%m%d_%H%M%S")

            # Get stats from backup
            conn = duckdb.connect(str(backup_file), read_only=True)
            stats = {
                "families": conn.execute(
                    "SELECT COUNT(*) FROM domain_families"
                ).fetchone()[0],
                "domains": conn.execute(
                    "SELECT COUNT(*) FROM domain_aliases"
                ).fetchone()[0],
                "names": conn.execute("SELECT COUNT(*) FROM company_names").fetchone()[
                    0
                ],
            }
            conn.close()

            versions.append(
                VersionInfo(
                    version=f"v{timestamp_str}",
                    created_at=created,
                    total_families=stats["families"],
                    total_domains=stats["domains"],
                    total_names=stats["names"],
                    file_path=str(backup_file),
                )
            )
        except Exception as e:
            print(f"Error reading backup {backup_file}: {e}")

    # Add current version
    current_db = db_dir / "foundrygraph.duckdb"
    if current_db.exists():
        conn = duckdb.connect(str(current_db), read_only=True)
        stats = {
            "families": conn.execute("SELECT COUNT(*) FROM domain_families").fetchone()[
                0
            ],
            "domains": conn.execute("SELECT COUNT(*) FROM domain_aliases").fetchone()[
                0
            ],
            "names": conn.execute("SELECT COUNT(*) FROM company_names").fetchone()[0],
        }
        conn.close()

        versions.insert(
            0,
            VersionInfo(
                version="current",
                created_at=datetime.fromtimestamp(current_db.stat().st_mtime),
                total_families=stats["families"],
                total_domains=stats["domains"],
                total_names=stats["names"],
                file_path=str(current_db),
            ),
        )

    return sorted(versions, key=lambda v: v.created_at, reverse=True)


@router.post("/create-version")
async def create_version(tag: Optional[str] = None, _: Any = Depends(require_admin)):
    """Create a tagged version of the current database"""
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    tag = tag or f"v{timestamp}"

    current_db = Path("config/foundrygraph.duckdb")
    if not current_db.exists():
        raise HTTPException(404, "Database not found")

    # Create versioned backup
    backup_path = Path(f"config/foundrygraph.duckdb.{tag}_{timestamp}")
    shutil.copy2(current_db, backup_path)

    # Store metadata
    metadata = {
        "tag": tag,
        "created_at": datetime.now().isoformat(),
        "file": str(backup_path),
        "stats": {},
    }

    # Get stats
    conn = duckdb.connect(str(current_db), read_only=True)
    metadata["stats"] = {
        "families": conn.execute("SELECT COUNT(*) FROM domain_families").fetchone()[0],
        "domains": conn.execute("SELECT COUNT(*) FROM domain_aliases").fetchone()[0],
        "names": conn.execute("SELECT COUNT(*) FROM company_names").fetchone()[0],
    }
    conn.close()

    # Save metadata
    metadata_file = backup_path.with_suffix(".json")
    with open(metadata_file, "w") as f:
        json.dump(metadata, f, indent=2)

    return {
        "message": f"Version {tag} created",
        "backup_path": str(backup_path),
        "metadata_path": str(metadata_file),
        "stats": metadata["stats"],
    }


@router.post("/validate-upload")
async def validate_company_file(
    file: UploadFile = File(...), _: Any = Depends(require_admin)
):
    """Validate an uploaded companies file"""
    # Save uploaded file temporarily
    temp_path = Path(f"/tmp/upload_{datetime.now().strftime('%Y%m%d_%H%M%S')}.yml")
    content = await file.read()

    with open(temp_path, "wb") as f:
        f.write(content)

    # Run validation
    from scripts.validate_companies import CompanyDataValidator

    validator = CompanyDataValidator()
    report = validator.validate_file(str(temp_path))

    # Clean up
    temp_path.unlink()

    return report


@router.post("/update")
async def update_domain_families(
    request: DomainUpdateRequest,
    background_tasks: BackgroundTasks,
    _: Any = Depends(require_admin),
):
    """Update domain families with new companies"""

    # Create version before update
    if not request.dry_run:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        await create_version(f"pre_update_{timestamp}")

    # Prepare update
    from scripts.update_domain_families import DomainFamilyUpdater

    updater = DomainFamilyUpdater()

    # Create temp file with companies
    temp_path = Path(f"/tmp/update_{datetime.now().strftime('%Y%m%d_%H%M%S')}.yml")
    with open(temp_path, "w") as f:
        yaml.dump({"companies": request.companies}, f)

    try:
        # Run update
        stats = updater.update_database(
            str(temp_path), resolution_mode=request.mode, dry_run=request.dry_run
        )

        # Generate report
        report = updater.generate_report()

        # Schedule metrics reset in background
        if not request.dry_run:
            background_tasks.add_task(reset_metrics_after_update)

        return {
            "success": True,
            "dry_run": request.dry_run,
            "stats": stats,
            "report": report,
        }

    except Exception as e:
        # Rollback on error
        if not request.dry_run:
            updater.rollback()
        raise HTTPException(500, f"Update failed: {str(e)}")

    finally:
        # Clean up temp file
        temp_path.unlink()


def reset_metrics_after_update():
    """Reset metrics after a successful update"""
    import time

    time.sleep(5)  # Give the registry time to reload
    METRICS["lookups"].clear()
    METRICS["unknowns"].clear()
    METRICS["last_reset"] = datetime.now()


# Export metrics tracking function for use in main lookup endpoints
def track_domain_lookup(domain: str, result: Optional[str]):
    """Public function to track domain lookups from other endpoints"""
    track_lookup(domain, result)


import time  # Add this import at the top
