"""Unit tests for metrics calculation."""

from datetime import timedelta

import pytest
from sqlmodel import Session

from agenteval.intelligent_eval import metrics
from agenteval.intelligent_eval.models import IntelligentEvalStatus
from agenteval.storage.db import (
    IntelligentEvalDB,
    IntelligentEvalTaskQueueDB,
    OpenClawCronPoolDB,
    utc_now,
)


def test_calculate_pool_utilization_empty(db_session: Session):
    """Test pool utilization when no crons exist."""
    utilization = metrics.calculate_pool_utilization(db_session)
    assert utilization == 0.0


def test_calculate_pool_utilization(db_session: Session):
    """Test pool utilization calculation."""
    # Create 10 crons: 6 busy, 4 idle
    for i in range(6):
        cron = OpenClawCronPoolDB(
            openclaw_cron_id=f"busy-{i}",
            status="busy",
            last_active_at=utc_now(),
        )
        db_session.add(cron)

    for i in range(4):
        cron = OpenClawCronPoolDB(
            openclaw_cron_id=f"idle-{i}",
            status="idle",
            last_active_at=utc_now(),
        )
        db_session.add(cron)

    db_session.commit()

    utilization = metrics.calculate_pool_utilization(db_session)
    assert utilization == 0.6


def test_calculate_task_backlog_empty(db_session: Session):
    """Test task backlog when no tasks exist."""
    backlog = metrics.calculate_task_backlog(db_session)
    assert backlog == 0


def test_calculate_task_backlog(db_session: Session):
    """Test task backlog calculation."""
    # Create 5 pending tasks
    for i in range(5):
        task = IntelligentEvalTaskQueueDB(
            eval_id=f"eval-{i}",
            status="pending",
            priority=1,
            reason="slot_due",
        )
        db_session.add(task)

    # Create 3 assigned tasks (not counted)
    for i in range(3):
        task = IntelligentEvalTaskQueueDB(
            eval_id=f"eval-assigned-{i}",
            status="assigned",
            priority=1,
            reason="slot_due",
        )
        db_session.add(task)

    db_session.commit()

    backlog = metrics.calculate_task_backlog(db_session)
    assert backlog == 5


def test_calculate_stuck_rate_empty(db_session: Session):
    """Test stuck rate when no crons exist."""
    rate = metrics.calculate_stuck_rate(db_session)
    assert rate == 0.0


def test_calculate_stuck_rate(db_session: Session):
    """Test stuck rate calculation."""
    # Create 10 crons: 2 stuck, 8 active
    for i in range(2):
        cron = OpenClawCronPoolDB(
            openclaw_cron_id=f"stuck-{i}",
            status="stuck",
            last_active_at=utc_now(),
        )
        db_session.add(cron)

    for i in range(8):
        cron = OpenClawCronPoolDB(
            openclaw_cron_id=f"active-{i}",
            status="busy",
            last_active_at=utc_now(),
        )
        db_session.add(cron)

    db_session.commit()

    rate = metrics.calculate_stuck_rate(db_session)
    assert rate == 0.2


def test_calculate_avg_processing_time_empty(db_session: Session):
    """Test average processing time when no completed tasks."""
    avg_time = metrics.calculate_avg_processing_time(db_session)
    assert avg_time is None


def test_calculate_avg_processing_time(db_session: Session):
    """Test average processing time calculation."""
    now = utc_now()

    # Create 3 completed tasks with different processing times
    task1 = IntelligentEvalTaskQueueDB(
        eval_id="eval-1",
        status="completed",
        priority=1,
        reason="slot_due",
        assigned_at=now - timedelta(minutes=10),
        completed_at=now - timedelta(minutes=5),
    )
    task2 = IntelligentEvalTaskQueueDB(
        eval_id="eval-2",
        status="completed",
        priority=1,
        reason="slot_due",
        assigned_at=now - timedelta(minutes=20),
        completed_at=now - timedelta(minutes=10),
    )
    task3 = IntelligentEvalTaskQueueDB(
        eval_id="eval-3",
        status="completed",
        priority=1,
        reason="slot_due",
        assigned_at=now - timedelta(minutes=30),
        completed_at=now - timedelta(minutes=15),
    )

    db_session.add_all([task1, task2, task3])
    db_session.commit()

    avg_time = metrics.calculate_avg_processing_time(db_session)
    # Average: (5 + 10 + 15) / 3 = 10 minutes = 600 seconds
    assert avg_time == 600.0


def test_calculate_eval_completion_rate_empty(db_session: Session):
    """Test eval completion rate when no evals exist."""
    rate = metrics.calculate_eval_completion_rate(db_session)
    assert rate == 0.0


def test_calculate_eval_completion_rate(db_session: Session):
    """Test eval completion rate calculation."""
    # Create 10 evals: 7 completed, 3 executing
    for i in range(7):
        eval_db = IntelligentEvalDB(
            name=f"eval-completed-{i}",
            target_id="target1",
            status=IntelligentEvalStatus.COMPLETED.value,
        )
        db_session.add(eval_db)

    for i in range(3):
        eval_db = IntelligentEvalDB(
            name=f"eval-executing-{i}",
            target_id="target1",
            status=IntelligentEvalStatus.EXECUTING.value,
        )
        db_session.add(eval_db)

    db_session.commit()

    rate = metrics.calculate_eval_completion_rate(db_session)
    assert rate == 0.7


def test_get_all_metrics(db_session: Session):
    """Test getting all metrics."""
    # 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()

    all_metrics = metrics.get_all_metrics(db_session)

    assert "pool_utilization" in all_metrics
    assert "task_backlog" in all_metrics
    assert "stuck_rate" in all_metrics
    assert "avg_processing_time_seconds" in all_metrics
    assert "eval_completion_rate" in all_metrics
    assert "timestamp" in all_metrics

    assert all_metrics["pool_utilization"] == 0.6
    assert all_metrics["task_backlog"] == 0
    assert all_metrics["stuck_rate"] == 0.0
