"""Soak test: sustained load + clean shutdown."""

import os
import sys
import time
import tracemalloc
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

from feid.agent import AgenteMaestroNASA
from feid.core import ConfigAgente


class SoakAgent(AgenteMaestroNASA):
    def _technical_work(self, task):
        time.sleep(0.001)
        return f"ok:{task}"


@pytest.mark.slow
def test_soak_15min_shutdown_under_load():
    if os.getenv("FEID_RUN_SOAK") != "1":
        pytest.skip("Set FEID_RUN_SOAK=1 to enable soak test")

    duration = int(os.getenv("FEID_SOAK_SECONDS", "900"))
    sample_every = int(os.getenv("FEID_SOAK_SAMPLE_SECONDS", "60"))
    max_mem_mb = int(os.getenv("FEID_SOAK_MAX_MEM_MB", "200"))
    max_pending = int(os.getenv("FEID_SOAK_MAX_PENDING", "50"))
    min_successes = int(os.getenv("FEID_SOAK_MIN_SUCCESSES", "200"))
    max_p95 = float(os.getenv("FEID_SOAK_MAX_P95", "0.2"))

    config = ConfigAgente(
        capacidad=2000,
        max_workers=4,
        backpressure_threshold=0.8,
        task_timeout_seconds=2.0,
        enable_rate_limiter=False,
        ttl_defecto=120.0,
    )
    agent = SoakAgent("SOAK", config=config, auto_persist=False)

    tracemalloc.start()
    start_snapshot = tracemalloc.take_snapshot()
    start_time = time.time()
    last_sample = start_time
    last_done = agent.global_metrics.get("successes", 0) + agent.global_metrics.get("ttl_deaths", 0)

    while (time.time() - start_time) < duration:
        for i in range(100):
            agent.send_task(
                f"load_{i}",
                complexity=2,
                backpressure=True,
                correlation_id="soak",
                ttl=120.0,
            )
        time.sleep(0.2)

        if (time.time() - last_sample) >= sample_every:
            current_done = agent.global_metrics.get("successes", 0) + agent.global_metrics.get("ttl_deaths", 0)
            assert current_done > last_done
            last_done = current_done
            elapsed = int(time.time() - start_time)
            print(
                f"[SOAK] t={elapsed}s successes={agent.global_metrics.get('successes', 0)} "
                f"ttl={agent.global_metrics.get('ttl_deaths', 0)} queue={agent.inbox.qsize()}"
            )
            last_sample = time.time()

    end_snapshot = tracemalloc.take_snapshot()
    stats = end_snapshot.compare_to(start_snapshot, "lineno")
    total_growth = sum(stat.size_diff for stat in stats)
    assert total_growth < (max_mem_mb * 1024 * 1024)

    pending_before = agent.inbox.qsize()
    stats = agent.graceful_shutdown(timeout=60.0)
    pending = stats["pending_queue"]
    assert pending >= 0
    if pending_before <= max_pending:
        assert pending <= max_pending
    else:
        assert pending < pending_before
    assert agent.global_metrics.get("successes", 0) >= min_successes
    p95 = agent.get_p95_latency()
    if p95 > 0:
        assert p95 <= max_p95
