"""Tests for performance metrics and decorators."""

from __future__ import annotations

import tempfile
import time
from pathlib import Path

import pytest

from cleave.core.performance import (
    get_metrics,
    memory_profiled,
    record_metric,
    timed,
)


def test_timed_decorator():
    """Test that @timed decorator tracks execution time."""

    @timed("test_operation")
    def slow_function():
        time.sleep(0.1)
        return "done"

    result = slow_function()
    assert result == "done"

    # Check metrics were recorded
    metrics = get_metrics()
    assert "test_operation" in metrics
    assert metrics["test_operation"]["count"] > 0
    assert metrics["test_operation"]["total_time"] >= 0.1
    assert metrics["test_operation"]["avg_time"] >= 0.1


def test_timed_decorator_with_args():
    """Test that @timed works with functions that have arguments."""

    @timed("add_operation")
    def add(a: int, b: int) -> int:
        return a + b

    result = add(2, 3)
    assert result == 5

    metrics = get_metrics()
    assert "add_operation" in metrics


def test_memory_profiled_decorator():
    """Test that @memory_profiled decorator tracks memory usage."""

    @memory_profiled("test_memory")
    def allocate_memory():
        # Allocate ~1MB
        data = [0] * (1024 * 1024 // 8)
        return len(data)

    result = allocate_memory()
    assert result > 0

    metrics = get_metrics()
    assert "test_memory" in metrics
    assert "peak_memory_mb" in metrics["test_memory"]


def test_record_metric():
    """Test manual metric recording."""
    record_metric("custom_metric", {
        "value": 42,
        "unit": "requests",
    })

    metrics = get_metrics()
    assert "custom_metric" in metrics
    assert metrics["custom_metric"]["value"] == 42


def test_metrics_persistence():
    """Test that metrics are persisted to ~/.cleave/performance.yaml."""
    with tempfile.TemporaryDirectory() as tmpdir:
        perf_file = Path(tmpdir) / "performance.yaml"

        # Record a metric
        record_metric("test_persistence", {"count": 1}, storage_path=perf_file)

        # Verify file exists
        assert perf_file.exists()

        # Read it back
        metrics = get_metrics(storage_path=perf_file)
        assert "test_persistence" in metrics


def test_metrics_aggregation():
    """Test that multiple calls to same operation aggregate correctly."""

    @timed("repeated_op")
    def repeat_me():
        time.sleep(0.01)

    # Call multiple times
    for _ in range(3):
        repeat_me()

    metrics = get_metrics()
    assert metrics["repeated_op"]["count"] == 3
    assert metrics["repeated_op"]["total_time"] >= 0.03


def test_first_token_latency():
    """Test tracking LLM first token latency."""
    record_metric("llm_response", {
        "first_token_latency": 0.5,
        "total_time": 2.0,
        "tokens": 150,
    })

    metrics = get_metrics()
    assert metrics["llm_response"]["first_token_latency"] == 0.5
    assert metrics["llm_response"]["tokens"] == 150


def test_workspace_size_tracking():
    """Test tracking workspace size metrics."""
    with tempfile.TemporaryDirectory() as tmpdir:
        workspace = Path(tmpdir)

        # Create some files
        (workspace / "file1.txt").write_text("a" * 1000)
        (workspace / "file2.txt").write_text("b" * 2000)

        from cleave.core.performance import record_workspace_metrics

        record_workspace_metrics(workspace)

        metrics = get_metrics()
        assert "workspace_size" in metrics
        assert metrics["workspace_size"]["total_bytes"] >= 3000
        assert metrics["workspace_size"]["file_count"] == 2


def test_file_io_latency():
    """Test tracking file I/O latency."""

    @timed("file_read")
    def read_file(path: Path) -> str:
        return path.read_text()

    with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
        f.write("test content")
        f.flush()
        temp_path = Path(f.name)

    try:
        content = read_file(temp_path)
        assert content == "test content"

        metrics = get_metrics()
        assert "file_read" in metrics
        assert metrics["file_read"]["avg_time"] > 0
    finally:
        temp_path.unlink()


def test_clear_metrics():
    """Test clearing metrics data."""
    record_metric("temp_metric", {"value": 1})

    from cleave.core.performance import clear_metrics
    clear_metrics()

    metrics = get_metrics()
    assert "temp_metric" not in metrics or metrics == {}
