"""Integration tests for metrics and alerts API."""

from datetime import timedelta

import pytest
from fastapi.testclient import TestClient
from sqlmodel import Session, SQLModel, create_engine, select
from unittest.mock import patch, MagicMock

from agenteval.intelligent_eval.models import IntelligentEvalStatus
from agenteval.storage.db import (
    IntelligentEvalDB,
    IntelligentEvalTaskQueueDB,
    OpenClawCronPoolDB,
    utc_now,
)
from agenteval.web.app import app
from agenteval.web.deps import get_db


@pytest.fixture()
def client(tmp_path):
    """Create a TestClient with a fresh database."""
    from agenteval.storage.db import (  # noqa: F401
        IntelligentEvalDB,
        IntelligentEvalTaskQueueDB,
        OpenClawCronPoolDB,
    )
    from agenteval.intelligent_eval.alerts import AlertHistoryDB

    engine = create_engine(
        f"sqlite:///{tmp_path / 'test.db'}",
        connect_args={"check_same_thread": False},
    )
    SQLModel.metadata.create_all(engine)
    session = Session(engine)

    def override_get_db():
        try:
            yield session
        finally:
            pass

    app.dependency_overrides[get_db] = override_get_db
    client = TestClient(app)
    yield client
    app.dependency_overrides.clear()
    session.close()
    engine.dispose()


@pytest.fixture()
def db_session(client):
    """Get the database session from the client fixture."""
    return next(app.dependency_overrides[get_db]())


def test_get_metrics_api(client: TestClient, db_session: Session):
    """Test getting metrics via API."""
    # Create some test data
    for i in range(5):
        cron = OpenClawCronPoolDB(
            openclaw_cron_id=f"cron-{i}",
            status="busy" if i < 3 else "idle",
            last_active_at=utc_now(),
        )
        db_session.add(cron)

    db_session.commit()

    response = client.get("/api/openclaw/cron-pool/metrics")
    assert response.status_code == 200

    data = response.json()
    assert "metrics" in data
    assert "pool_utilization" in data["metrics"]
    assert "task_backlog" in data["metrics"]
    assert "stuck_rate" in data["metrics"]
    assert "avg_processing_time_seconds" in data["metrics"]
    assert "eval_completion_rate" in data["metrics"]

    assert data["metrics"]["pool_utilization"] == 0.6


def test_check_alerts_api_no_alerts(client: TestClient, db_session: Session):
    """Test checking alerts when no rules are triggered."""
    # Create healthy state
    for i in range(5):
        cron = OpenClawCronPoolDB(
            openclaw_cron_id=f"cron-{i}",
            status="idle",
            last_active_at=utc_now(),
        )
        db_session.add(cron)

    db_session.commit()

    response = client.post("/api/openclaw/cron-pool/check-alerts")
    assert response.status_code == 200

    data = response.json()
    assert data["success"] is True
    assert data["alerts_triggered"] == 0


def test_check_alerts_api_with_alerts(client: TestClient, db_session: Session):
    """Test checking alerts when rules are triggered."""
    # Create high backlog
    for i in range(60):
        task = IntelligentEvalTaskQueueDB(
            eval_id=f"eval-{i}",
            status="pending",
            priority=1,
            reason="slot_due",
        )
        db_session.add(task)

    db_session.commit()

    response = client.post("/api/openclaw/cron-pool/check-alerts")
    assert response.status_code == 200

    data = response.json()
    assert data["success"] is True
    assert data["alerts_triggered"] > 0

    # Should have task_backlog alert
    backlog_alerts = [a for a in data["alerts"] if a["alert_type"] == "task_backlog"]
    assert len(backlog_alerts) == 1
    assert backlog_alerts[0]["metric_value"] == 60


def test_get_alert_history_api(client: TestClient, db_session: Session):
    """Test getting alert history via API."""
    # Create some alerts
    from agenteval.intelligent_eval.alerts import AlertHistoryDB

    for i in range(3):
        alert = AlertHistoryDB(
            id=f"alert-{i}",
            alert_type="task_backlog",
            severity="warning",
            message=f"Test alert {i}",
            metric_value=50 + i,
            threshold=50,
        )
        db_session.add(alert)

    db_session.commit()

    response = client.get("/api/openclaw/cron-pool/alerts")
    assert response.status_code == 200

    data = response.json()
    assert "alerts" in data
    assert len(data["alerts"]) == 3


def test_get_alert_history_unresolved_only(client: TestClient, db_session: Session):
    """Test getting unresolved alerts only."""
    from agenteval.intelligent_eval.alerts import AlertHistoryDB

    # Create resolved and unresolved alerts
    alert1 = AlertHistoryDB(
        id="alert-1",
        alert_type="task_backlog",
        severity="warning",
        message="Test alert 1",
        metric_value=60,
        threshold=50,
    )
    alert2 = AlertHistoryDB(
        id="alert-2",
        alert_type="stuck_rate",
        severity="critical",
        message="Test alert 2",
        metric_value=0.2,
        threshold=0.1,
        resolved_at=utc_now(),
    )

    db_session.add_all([alert1, alert2])
    db_session.commit()

    response = client.get("/api/openclaw/cron-pool/alerts?unresolved_only=true")
    assert response.status_code == 200

    data = response.json()
    assert len(data["alerts"]) == 1
    assert data["alerts"][0]["id"] == "alert-1"


def test_resolve_alert_api(client: TestClient, db_session: Session):
    """Test resolving an alert via API."""
    from agenteval.intelligent_eval.alerts import AlertHistoryDB

    alert = AlertHistoryDB(
        id="alert-1",
        alert_type="task_backlog",
        severity="warning",
        message="Test alert",
        metric_value=60,
        threshold=50,
    )
    db_session.add(alert)
    db_session.commit()

    response = client.post("/api/openclaw/cron-pool/alerts/alert-1/resolve")
    assert response.status_code == 200

    data = response.json()
    assert data["success"] is True

    # Verify alert is resolved
    db_session.refresh(alert)
    assert alert.resolved_at is not None


def test_resolve_nonexistent_alert_api(client: TestClient):
    """Test resolving a non-existent alert."""
    response = client.post("/api/openclaw/cron-pool/alerts/nonexistent/resolve")
    assert response.status_code == 404


def test_end_to_end_metrics_and_alerts(client: TestClient, db_session: Session):
    """Test end-to-end metrics and alerts flow."""
    # Create high utilization state
    for i in range(19):
        cron = OpenClawCronPoolDB(
            openclaw_cron_id=f"busy-{i}",
            status="busy",
            last_active_at=utc_now(),
        )
        db_session.add(cron)

    cron = OpenClawCronPoolDB(
        openclaw_cron_id="idle-0",
        status="idle",
        last_active_at=utc_now(),
    )
    db_session.add(cron)

    # Create high backlog
    for i in range(60):
        task = IntelligentEvalTaskQueueDB(
            eval_id=f"eval-{i}",
            status="pending",
            priority=1,
            reason="slot_due",
        )
        db_session.add(task)

    db_session.commit()

    # Get metrics
    response = client.get("/api/openclaw/cron-pool/metrics")
    assert response.status_code == 200
    metrics_data = response.json()["metrics"]
    assert metrics_data["pool_utilization"] == 0.95
    assert metrics_data["task_backlog"] == 60

    # Check alerts
    response = client.post("/api/openclaw/cron-pool/check-alerts")
    assert response.status_code == 200
    alerts_data = response.json()
    assert alerts_data["alerts_triggered"] > 0

    # Get alert history
    response = client.get("/api/openclaw/cron-pool/alerts")
    assert response.status_code == 200
    history_data = response.json()
    assert len(history_data["alerts"]) > 0

    # Resolve first alert
    if history_data["alerts"]:
        alert_id = history_data["alerts"][0]["id"]
        response = client.post(f"/api/openclaw/cron-pool/alerts/{alert_id}/resolve")
        assert response.status_code == 200
