from __future__ import annotations

from types import SimpleNamespace
from unittest.mock import patch

from django.test import TestCase, override_settings
from rest_framework.test import APIClient

from irrigation.indicators import WaterStressService


@override_settings(ROOT_URLCONF="irrigation.urls")
class WaterStressApiTests(TestCase):
    def setUp(self):
        self.client = APIClient()

    @patch("irrigation.views.apps.get_app_config")
    def test_water_stress_api_returns_payload(self, mock_get_app_config):
        mock_service = SimpleNamespace(
            get_water_stress=lambda **_kwargs: {
                "farm_uuid": "550e8400-e29b-41d4-a716-446655440000",
                "waterStressIndex": 12,
                "level": "پایین",
                "sourceMetric": {"soilMoisture": 46.0},
            }
        )
        mock_get_app_config.return_value = SimpleNamespace(
            get_water_stress_service=lambda: mock_service
        )

        response = self.client.post(
            "/water-stress/",
            data={
                "farm_uuid": "550e8400-e29b-41d4-a716-446655440000",
                "irrigation_recommendation": {"events": [{"date": "2026-04-25", "amount": 2.5}]},
                "fertilization_recommendation": {
                    "events": [{"date": "2026-04-20", "N_amount": 45, "N_recovery": 0.7}]
                },
            },
            format="json",
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["data"]["waterStressIndex"], 12)


class WaterStressServiceTests(TestCase):
    @patch("irrigation.indicators.apps.get_app_config")
    @patch("irrigation.indicators.SensorData.objects.filter")
    def test_service_uses_crop_simulation_water_stress(self, mock_filter, mock_get_app_config):
        mock_filter.return_value.first.return_value = SimpleNamespace(
            farm_uuid="550e8400-e29b-41d4-a716-446655440000",
            soil_moisture=46.0,
        )
        mock_service = SimpleNamespace(
            get_water_stress=lambda **_kwargs: {
                "farm_uuid": "550e8400-e29b-41d4-a716-446655440000",
                "plant_name": "Tomato",
                "waterStressIndex": 37,
                "level": "متوسط",
                "sourceMetric": {"engine": "crop_simulation"},
            }
        )
        mock_get_app_config.return_value = SimpleNamespace(
            get_water_stress_service=lambda: mock_service
        )

        payload = WaterStressService().get_water_stress(
            farm_uuid="550e8400-e29b-41d4-a716-446655440000"
        )

        self.assertEqual(payload["waterStressIndex"], 37)
        self.assertEqual(payload["sourceMetric"]["engine"], "crop_simulation")

    @patch("irrigation.indicators.apps.get_app_config")
    @patch("irrigation.indicators.SensorData.objects.filter")
    def test_service_raises_when_crop_simulation_fails(self, mock_filter, mock_get_app_config):
        mock_filter.return_value.first.return_value = SimpleNamespace(
            farm_uuid="550e8400-e29b-41d4-a716-446655440000",
            soil_moisture=46.0,
        )

        class BrokenService:
            def get_water_stress(self, **_kwargs):
                raise RuntimeError("simulation offline")

        mock_get_app_config.return_value = SimpleNamespace(
            get_water_stress_service=lambda: BrokenService()
        )

        with self.assertRaises(RuntimeError):
            WaterStressService().get_water_stress(
                farm_uuid="550e8400-e29b-41d4-a716-446655440000"
            )
