from __future__ import annotations

import uuid
from unittest.mock import patch

from django.test import override_settings

from farm_data.models import ParameterUpdateLog, PlantCatalogSnapshot, SensorData, SensorParameter
from integration_tests.base import IntegrationAPITestCase


@override_settings(ROOT_URLCONF="config.urls")
class FarmManagementJourneyTests(IntegrationAPITestCase):
    def test_full_management_journey_persists_farm_related_records(self) -> None:
        primary_method = self.create_irrigation_method_via_api("Drip Prime")
        backup_method = self.create_irrigation_method_via_api(
            "Sprinkler Backup",
            category="pressure",
            water_efficiency_percent=78.0,
        )

        irrigation_list_response = self.client.get("/api/irrigation/")
        self.assertEqual(irrigation_list_response.status_code, 200)
        self.assertGreaterEqual(len(irrigation_list_response.json()["data"]), 2)
        irrigation_detail_response = self.client.get(f"/api/irrigation/{primary_method['id']}/")
        self.assertEqual(irrigation_detail_response.status_code, 200)
        self.assertEqual(irrigation_detail_response.json()["data"]["name"], "Drip Prime")

        moisture_parameter = self.create_sensor_parameter_via_api()
        self.assertEqual(moisture_parameter["action"], ParameterUpdateLog.ACTION_ADDED)
        self.assertTrue(
            SensorParameter.objects.filter(sensor_key="sensor-7-1", code="soil_moisture").exists()
        )

        moisture_parameter_update = self.create_sensor_parameter_via_api(
            metadata={"min": 5, "max": 85, "ui": "gauge"},
        )
        self.assertEqual(moisture_parameter_update["action"], ParameterUpdateLog.ACTION_MODIFIED)
        self.assertEqual(
            ParameterUpdateLog.objects.filter(parameter__code="soil_moisture").count(),
            2,
        )

        tomato = self.create_plant_via_api("Tomato")
        cucumber = self.create_plant_via_api("Cucumber", watering="daily")

        plant_catalog = self.create_plant_via_api(
            "Pepper",
            growth_stage="",
            icon="",
        )
        pepper = PlantCatalogSnapshot.objects.get(backend_plant_id=plant_catalog["id"])
        self.assertEqual(pepper.icon, "leaf")
        self.assertEqual(pepper.growth_stages, [])

        updated_tomato = self.create_plant_via_api(
            "Tomato",
            id=tomato["id"],
            growth_stage="flowering",
            growth_stages=["flowering"],
            watering="daily",
        )
        self.assertEqual(updated_tomato["growth_stage"], "flowering")
        self.assertEqual(
            PlantCatalogSnapshot.objects.get(backend_plant_id=tomato["id"]).growth_stage,
            "flowering",
        )

        updated_cucumber = self.create_plant_via_api(
            "Cucumber",
            id=cucumber["id"],
            light="full sun",
            watering="every day",
            soil="sandy loam",
            temperature="18-30C",
            growth_stage="fruiting",
            growth_stages=["fruiting"],
            planting_season="spring",
            harvest_time="70 days",
            spacing="40 cm",
            fertilizer="potassium rich",
        )
        self.assertEqual(updated_cucumber["watering"], "every day")

        farm_uuid = uuid.uuid4()
        created_farm = self.upsert_farm_via_api(
            farm_uuid=farm_uuid,
            plant_ids=[tomato["id"], cucumber["id"]],
            irrigation_method_id=primary_method["id"],
            sensor_payload={
                "sensor-7-1": {
                    "soil_moisture": 41.2,
                    "soil_temperature": 23.4,
                    "soil_ph": 6.8,
                    "electrical_conductivity": 1.1,
                    "nitrogen": 17.0,
                    "phosphorus": 12.5,
                    "potassium": 21.0,
                }
            },
        )
        self.assertEqual(created_farm["farm_uuid"], str(farm_uuid))
        farm_record = SensorData.objects.get(farm_uuid=farm_uuid)
        self.assertCountEqual(
            list(farm_record.plant_assignments.values_list("plant__backend_plant_id", flat=True)),
            [tomato["id"], cucumber["id"]],
        )
        self.assertEqual(farm_record.irrigation_method_id, primary_method["id"])
        self.assertEqual(farm_record.center_location_id, self.primary_location.id)

        updated_farm = self.upsert_farm_via_api(
            farm_uuid=farm_uuid,
            plant_ids=[tomato["id"]],
            irrigation_method_id=backup_method["id"],
            sensor_payload={
                "sensor-7-1": {
                    "nitrogen": 19.5,
                    "soil_moisture": 44.0,
                },
                "leaf-sensor": {
                    "leaf_wetness": 11.0,
                    "leaf_temperature": 21.3,
                },
            },
        )
        self.assertEqual(updated_farm["irrigation_method_id"], backup_method["id"])

        farm_record.refresh_from_db()
        self.assertEqual(farm_record.irrigation_method_id, backup_method["id"])
        self.assertCountEqual(
            list(farm_record.plant_assignments.values_list("plant__backend_plant_id", flat=True)),
            [tomato["id"]],
        )
        self.assertEqual(farm_record.sensor_payload["sensor-7-1"]["soil_temperature"], 23.4)
        self.assertEqual(farm_record.sensor_payload["sensor-7-1"]["soil_moisture"], 44.0)
        self.assertEqual(farm_record.sensor_payload["sensor-7-1"]["nitrogen"], 19.5)
        self.assertEqual(farm_record.sensor_payload["leaf-sensor"]["leaf_wetness"], 11.0)
        self.assertTrue(
            SensorParameter.objects.filter(sensor_key="leaf-sensor", code="leaf_wetness").exists()
        )

        farm_detail_response = self.client.get(f"/api/farm-data/{farm_uuid}/detail/")
        self.assertEqual(farm_detail_response.status_code, 200)
        farm_detail = farm_detail_response.json()["data"]
        self.assertEqual(farm_detail["center_location"]["id"], self.primary_location.id)
        self.assertEqual(farm_detail["irrigation_method_id"], backup_method["id"])
        self.assertEqual(farm_detail["plant_ids"], [tomato["id"]])
        self.assertEqual(farm_detail["plants"][0]["name"], "Tomato")
        self.assertEqual(
            farm_detail["sensor_payload"]["leaf-sensor"]["leaf_temperature"],
            21.3,
        )
        self.assertCountEqual(
            [item["code"] for item in farm_detail["sensor_schema"]["leaf-sensor"]],
            ["leaf_temperature", "leaf_wetness"],
        )
