"""Tests for aicert_pro.baseline module."""

import json
import tempfile
from pathlib import Path
from datetime import datetime

import pytest

from aicert_pro.baseline import (
    provider_key,
    load_baseline,
    save_baseline,
    baseline_path,
    save_from_run,
    check_from_run,
)


class TestProviderKey:
    """Tests for provider_key function."""

    def test_without_temperature(self):
        """Test provider key without temperature."""
        key = provider_key("anthropic", "claude-3-5-sonnet-20241022", None)
        assert key == "anthropic/claude-3-5-sonnet-20241022"

    def test_with_temperature(self):
        """Test provider key with temperature."""
        key = provider_key("openai", "gpt-4o", 0.5)
        assert key == "openai/gpt-4o_0.5"

    def test_with_zero_temperature(self):
        """Test provider key with zero temperature."""
        key = provider_key("openai", "gpt-4o", 0.0)
        assert key == "openai/gpt-4o_0.0"


class TestBaselinePath:
    """Tests for baseline_path function."""

    def test_default_baseline_dir(self, tmp_path, monkeypatch):
        """Test baseline path with default directory."""
        monkeypatch.setattr(Path, "home", lambda: tmp_path)
        path = baseline_path("test-project", None)
        expected = tmp_path / ".aicert" / "baselines" / "test-project.json"
        assert path == expected

    def test_custom_baseline_dir(self, tmp_path):
        """Test baseline path with custom directory."""
        path = baseline_path("test-project", tmp_path / "custom")
        expected = tmp_path / "custom" / "test-project.json"
        assert path == expected


class TestLoadSaveBaseline:
    """Tests for load_baseline and save_baseline functions."""

    def test_save_and_load_baseline(self, tmp_path):
        """Test saving and loading baseline data."""
        path = tmp_path / "baseline.json"
        data = {
            "project": "test-project",
            "metrics": {
                "stability": 95.5,
                "compliance": 98.0,
                "p95_latency_ms": 1500,
            }
        }
        save_baseline(path, data)
        loaded = load_baseline(path)
        assert loaded == data


class TestSaveFromRun:
    """Tests for save_from_run function."""

    def test_save_from_run(self, tmp_path):
        """Test saving baseline from run directory."""
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        summary = {
            "project": "my-project",
            "provider": "anthropic",
            "model": "claude-3-5-sonnet-20241022",
            "temperature": 0.5,
            "timestamp": "2024-01-15T10:00:00Z",
            "metrics": {
                "stability": 92.5,
                "compliance": 97.0,
                "p95_latency_ms": 2000,
                "mean_latency_ms": 1500,
                "mean_cost_usd": 0.05,
            },
            "prompt_hash": "abc123",
            "schema_hash": "def456",
        }
        
        with open(run_dir / "summary.json", "w") as f:
            json.dump(summary, f)
        
        baseline_dir = tmp_path / "baselines"
        data = save_from_run(run_dir, baseline_dir)
        
        assert data["project"] == "my-project"
        assert data["provider_key"] == "anthropic/claude-3-5-sonnet-20241022_0.5"
        assert data["metrics"]["stability"] == 92.5
        assert data["metrics"]["compliance"] == 97.0
        assert data["metrics"]["p95_latency_ms"] == 2000
        assert data["metrics"]["mean_latency_ms"] == 1500
        assert data["metrics"]["mean_cost_usd"] == 0.05
        assert data["metrics"]["prompt_hash"] == "abc123"
        assert data["metrics"]["schema_hash"] == "def456"
        
        # Verify file was saved
        baseline_file = baseline_dir / "my-project.json"
        assert baseline_file.exists()

    def test_save_from_run_missing_summary(self, tmp_path):
        """Test that missing summary.json raises error."""
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        with pytest.raises(FileNotFoundError):
            save_from_run(run_dir, None)


class TestCheckFromRun:
    """Tests for check_from_run function."""

    def test_check_from_run_passes(self, tmp_path):
        """Test check passes when metrics are within thresholds."""
        baseline_dir = tmp_path / "baselines"
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        # Create baseline
        baseline = {
            "project": "my-project",
            "metrics": {
                "stability": 95.0,
                "compliance": 98.0,
                "p95_latency_ms": 1000,
                "mean_cost_usd": 0.05,
            }
        }
        save_baseline(baseline_dir / "my-project.json", baseline)
        
        # Create summary with same metrics
        summary = {
            "project": "my-project",
            "metrics": {
                "stability": 94.0,  # 1 point drop (within 5)
                "compliance": 97.5,  # 0.5 point drop (within 2)
                "p95_latency_ms": 1100,  # 10% increase (within 25%)
                "mean_cost_usd": 0.055,  # 10% increase (within 20%)
            }
        }
        with open(run_dir / "summary.json", "w") as f:
            json.dump(summary, f)
        
        result = check_from_run(run_dir, baseline_dir)
        assert result is True

    def test_check_from_run_stability_failure(self, tmp_path):
        """Test check fails when stability drops too much."""
        baseline_dir = tmp_path / "baselines"
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        baseline = {
            "project": "my-project",
            "metrics": {
                "stability": 95.0,
                "compliance": 98.0,
                "p95_latency_ms": 1000,
            }
        }
        save_baseline(baseline_dir / "my-project.json", baseline)
        
        summary = {
            "project": "my-project",
            "metrics": {
                "stability": 85.0,  # 10 point drop (exceeds 5)
                "compliance": 97.0,
                "p95_latency_ms": 1000,
            }
        }
        with open(run_dir / "summary.json", "w") as f:
            json.dump(summary, f)
        
        result = check_from_run(run_dir, baseline_dir)
        assert result is False

    def test_check_from_run_compliance_failure(self, tmp_path):
        """Test check fails when compliance drops too much."""
        baseline_dir = tmp_path / "baselines"
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        baseline = {
            "project": "my-project",
            "metrics": {
                "stability": 95.0,
                "compliance": 98.0,
                "p95_latency_ms": 1000,
            }
        }
        save_baseline(baseline_dir / "my-project.json", baseline)
        
        summary = {
            "project": "my-project",
            "metrics": {
                "stability": 94.0,
                "compliance": 90.0,  # 8 point drop (exceeds 2)
                "p95_latency_ms": 1000,
            }
        }
        with open(run_dir / "summary.json", "w") as f:
            json.dump(summary, f)
        
        result = check_from_run(run_dir, baseline_dir)
        assert result is False

    def test_check_from_run_latency_failure(self, tmp_path):
        """Test check fails when P95 latency regresses too much."""
        baseline_dir = tmp_path / "baselines"
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        baseline = {
            "project": "my-project",
            "metrics": {
                "stability": 95.0,
                "compliance": 98.0,
                "p95_latency_ms": 1000,
            }
        }
        save_baseline(baseline_dir / "my-project.json", baseline)
        
        summary = {
            "project": "my-project",
            "metrics": {
                "stability": 94.0,
                "compliance": 97.0,
                "p95_latency_ms": 1500,  # 50% increase (exceeds 25%)
            }
        }
        with open(run_dir / "summary.json", "w") as f:
            json.dump(summary, f)
        
        result = check_from_run(run_dir, baseline_dir)
        assert result is False

    def test_check_from_run_cost_failure(self, tmp_path):
        """Test check fails when cost regresses too much."""
        baseline_dir = tmp_path / "baselines"
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        baseline = {
            "project": "my-project",
            "metrics": {
                "stability": 95.0,
                "compliance": 98.0,
                "p95_latency_ms": 1000,
                "mean_cost_usd": 0.05,
            }
        }
        save_baseline(baseline_dir / "my-project.json", baseline)
        
        summary = {
            "project": "my-project",
            "metrics": {
                "stability": 94.0,
                "compliance": 97.0,
                "p95_latency_ms": 1000,
                "mean_cost_usd": 0.07,  # 40% increase (exceeds 20%)
            }
        }
        with open(run_dir / "summary.json", "w") as f:
            json.dump(summary, f)
        
        result = check_from_run(run_dir, baseline_dir)
        assert result is False

    def test_check_from_run_missing_baseline(self, tmp_path):
        """Test check fails when baseline doesn't exist."""
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        summary = {
            "project": "unknown-project",
            "metrics": {
                "stability": 95.0,
            }
        }
        with open(run_dir / "summary.json", "w") as f:
            json.dump(summary, f)
        
        with pytest.raises(FileNotFoundError):
            check_from_run(run_dir, tmp_path)

    def test_check_from_run_missing_summary(self, tmp_path):
        """Test check fails when summary doesn't exist."""
        baseline_dir = tmp_path / "baselines"
        run_dir = tmp_path / "run"
        run_dir.mkdir()
        
        baseline = {
            "project": "my-project",
            "metrics": {
                "stability": 95.0,
            }
        }
        save_baseline(baseline_dir / "my-project.json", baseline)
        
        with pytest.raises(FileNotFoundError):
            check_from_run(run_dir, baseline_dir)
