"""Baseline regression enforcement for aicert-pro."""

import json
from pathlib import Path
from typing import Any

# Default thresholds for regression detection
DEFAULT_MAX_STABILITY_DROP = 5
DEFAULT_MAX_COMPLIANCE_DROP = 2
DEFAULT_MAX_P95_LATENCY_REGRESSION_PCT = 25
DEFAULT_MAX_COST_REGRESSION_PCT = 20


def provider_key(provider: str, model: str, temperature: float | None) -> str:
    """Generate unique provider key for baseline tracking.
    
    Args:
        provider: Provider name (e.g., "anthropic", "openai").
        model: Model name (e.g., "claude-3-5-sonnet-20241022").
        temperature: Temperature setting or None.
        
    Returns:
        Unique key string combining provider, model, and temperature.
    """
    temp_str = f"_{temperature}" if temperature is not None else ""
    return f"{provider}/{model}{temp_str}"


def load_baseline(path: Path) -> dict:
    """Load baseline data from JSON file.
    
    Args:
        path: Path to baseline JSON file.
        
    Returns:
        Baseline data dictionary.
    """
    with open(path, "r") as f:
        return json.load(f)


def save_baseline(path: Path, data: dict) -> None:
    """Save baseline data to JSON file.
    
    Args:
        path: Path to save baseline JSON file.
        data: Baseline data dictionary.
    """
    path.parent.mkdir(parents=True, exist_ok=True)
    with open(path, "w") as f:
        json.dump(data, f, indent=2)


def baseline_path(project: str, baseline_dir: Path | None) -> Path:
    """Get baseline file path for a project.
    
    Args:
        project: Project name.
        baseline_dir: Directory to store baselines, or None for default.
        
    Returns:
        Path to baseline JSON file.
    """
    if baseline_dir is None:
        baseline_dir = Path.home() / ".aicert" / "baselines"
    baseline_dir.mkdir(parents=True, exist_ok=True)
    return baseline_dir / f"{project}.json"


def save_from_run(run_dir: Path, baseline_dir: Path | None = None) -> dict:
    """Save baseline metrics from a run directory.
    
    Reads summary.json from the run directory and saves provider metrics
    to the baseline store.
    
    Args:
        run_dir: Path to run directory containing summary.json.
        baseline_dir: Directory to store baselines, or None for default.
        
    Returns:
        The saved baseline data dictionary.
    """
    summary_path = run_dir / "summary.json"
    if not summary_path.exists():
        raise FileNotFoundError(f"summary.json not found in {run_dir}")
    
    with open(summary_path, "r") as f:
        summary = json.load(f)
    
    project = summary.get("project", "default")
    
    # Extract provider metrics from summary
    metrics = summary.get("metrics", {})
    provider = summary.get("provider", "")
    model = summary.get("model", "")
    temperature = summary.get("temperature")
    
    provider_key_str = provider_key(provider, model, temperature)
    
    baseline_data = {
        "project": project,
        "provider_key": provider_key_str,
        "created_at": summary.get("timestamp", ""),
        "metrics": {
            "stability": metrics.get("stability", 0),
            "compliance": metrics.get("compliance", 0),
            "p95_latency_ms": metrics.get("p95_latency_ms", 0),
            "mean_latency_ms": metrics.get("mean_latency_ms", 0),
            "mean_cost_usd": metrics.get("mean_cost_usd"),
            "prompt_hash": summary.get("prompt_hash", ""),
            "schema_hash": summary.get("schema_hash", ""),
        }
    }
    
    # Remove None values
    baseline_data["metrics"] = {k: v for k, v in baseline_data["metrics"].items() if v is not None}
    
    path = baseline_path(project, baseline_dir)
    save_baseline(path, baseline_data)
    
    return baseline_data


def check_from_run(
    run_dir: Path,
    baseline_dir: Path | None = None,
    max_stability_drop: int = DEFAULT_MAX_STABILITY_DROP,
    max_compliance_drop: int = DEFAULT_MAX_COMPLIANCE_DROP,
    max_p95_latency_regression_pct: int = DEFAULT_MAX_P95_LATENCY_REGRESSION_PCT,
    max_cost_regression_pct: int = DEFAULT_MAX_COST_REGRESSION_PCT,
) -> bool:
    """Check current run against baseline for regressions.
    
    Args:
        run_dir: Path to run directory containing summary.json.
        baseline_dir: Directory to store baselines, or None for default.
        max_stability_drop: Maximum allowed stability drop (percentage points).
        max_compliance_drop: Maximum allowed compliance drop (percentage points).
        max_p95_latency_regression_pct: Maximum allowed P95 latency regression (%).
        max_cost_regression_pct: Maximum allowed cost regression (%).
        
    Returns:
        True if all metrics pass baseline thresholds, False otherwise.
    """
    summary_path = run_dir / "summary.json"
    if not summary_path.exists():
        raise FileNotFoundError(f"summary.json not found in {run_dir}")
    
    with open(summary_path, "r") as f:
        summary = json.load(f)
    
    project = summary.get("project", "default")
    baseline_file = baseline_path(project, baseline_dir)
    
    if not baseline_file.exists():
        raise FileNotFoundError(f"Baseline not found for project '{project}'. Run 'baseline save' first.")
    
    baseline = load_baseline(baseline_file)
    baseline_metrics = baseline.get("metrics", {})
    current_metrics = summary.get("metrics", {})
    
    failures: list[str] = []
    
    # Check stability drop
    baseline_stability = baseline_metrics.get("stability", 0)
    current_stability = current_metrics.get("stability", 0)
    stability_drop = baseline_stability - current_stability
    if stability_drop > max_stability_drop:
        failures.append(
            f"Stability dropped by {stability_drop:.1f} (max: {max_stability_drop})"
        )
    
    # Check compliance drop
    baseline_compliance = baseline_metrics.get("compliance", 0)
    current_compliance = current_metrics.get("compliance", 0)
    compliance_drop = baseline_compliance - current_compliance
    if compliance_drop > max_compliance_drop:
        failures.append(
            f"Compliance dropped by {compliance_drop:.1f} (max: {max_compliance_drop})"
        )
    
    # Check P95 latency regression
    baseline_p95 = baseline_metrics.get("p95_latency_ms", 0)
    current_p95 = current_metrics.get("p95_latency_ms", 0)
    if baseline_p95 > 0 and current_p95 > 0:
        p95_regression_pct = ((current_p95 - baseline_p95) / baseline_p95) * 100
        if p95_regression_pct > max_p95_latency_regression_pct:
            failures.append(
                f"P95 latency regressed by {p95_regression_pct:.1f}% (max: {max_p95_latency_regression_pct}%)"
            )
    
    # Check cost regression
    baseline_cost = baseline_metrics.get("mean_cost_usd")
    current_cost = current_metrics.get("mean_cost_usd")
    if baseline_cost is not None and current_cost is not None and baseline_cost > 0:
        cost_regression_pct = ((current_cost - baseline_cost) / baseline_cost) * 100
        if cost_regression_pct > max_cost_regression_pct:
            failures.append(
                f"Cost regressed by {cost_regression_pct:.1f}% (max: {max_cost_regression_pct}%)"
            )
    
    if failures:
        print("Baseline regression detected:")
        for failure in failures:
            print(f"  - {failure}")
        return False
    
    print("All metrics pass baseline thresholds.")
    return True
