"""
Load test for the crop analysis API using Locust.

Simulates realistic usage: a farmer/officer submits an analysis
request, then polls the task status endpoint until it completes —
exactly the two-step flow the real frontend uses.

Usage:
    locust -f tests/load/locustfile.py --host=https://your-domain.com

Then open http://localhost:8089 to configure user count and spawn rate,
and watch live latency/failure graphs. For the "high scale from day
one" requirement, start by simulating realistic peak load (e.g. 50-200
concurrent users) and look specifically at:
  - p95/p99 latency on /analyze (should stay low — it's async, just queues)
  - time-to-completion via polling (this is where ML+LLM time shows up)
  - error rate under sustained load
"""

import random
import time

from locust import HttpUser, between, task

API_KEY = "test-key-123"  # replace with a real test API key for the target environment

CROPS = ["rice", "wheat", "maize", "cotton", "groundnut", "sugarcane", "sorghum"]
DISTRICTS = ["thanjavur", "madurai", "coimbatore", "salem", "tirunelveli"]
MONTHS = list(range(1, 13))


class CropAnalysisUser(HttpUser):
    wait_time = between(2, 8)  # simulate realistic human pacing between requests

    def on_start(self):
        self.client.headers.update({"X-API-Key": API_KEY})

    @task(10)
    def analyze_and_poll(self):
        payload = {
            "crop": random.choice(CROPS),
            "location": random.choice(DISTRICTS),
            "month": random.choice(MONTHS),
        }

        with self.client.post("/api/v1/analyze", json=payload, catch_response=True) as response:
            if response.status_code != 202:
                response.failure(f"Expected 202, got {response.status_code}")
                return

            task_id = response.json().get("task_id")
            if not task_id:
                response.failure("No task_id in response")
                return

        self._poll_until_complete(task_id)

    def _poll_until_complete(self, task_id: str, max_attempts: int = 20, interval_seconds: float = 1.5):
        for _ in range(max_attempts):
            with self.client.get(
                f"/api/v1/tasks/{task_id}", catch_response=True, name="/api/v1/tasks/[id]"
            ) as response:
                if response.status_code != 200:
                    response.failure(f"Polling failed with {response.status_code}")
                    return

                status = response.json().get("status")
                if status == "completed":
                    response.success()
                    return
                if status == "failed":
                    response.failure("Task reported failure")
                    return
                response.success()  # still queued/running — this poll itself succeeded

            time.sleep(interval_seconds)

        # If we exit the loop, the task never completed within the budget —
        # this is a real signal worth seeing in the load test report.

    @task(2)
    def check_health(self):
        self.client.get("/api/v1/health/live", name="/api/v1/health/live")

    @task(1)
    def list_crops(self):
        self.client.get("/api/v1/crops", name="/api/v1/crops")
