from __future__ import annotations

from datetime import UTC, datetime
from uuid import uuid4

import pytest
from fastapi.testclient import TestClient

from app.modules.zootech.catalog_apply import apply_catalog_change
from tests.orchestrator_dual_harness import make_enterprise


def test_wesp_compat_feed_dispensers(client: TestClient):
    enterprise_id = make_enterprise(client)
    login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
    token = login.json()["access_token"]
    session = client.post(
        f"/api/v1/enterprise/enterprises/{enterprise_id}/session",
        headers={"Authorization": f"Bearer {token}"},
    )
    token = session.json()["access_token"]
    headers = {"Authorization": f"Bearer {token}"}
    resp = client.get(f"/api/feed_dispensers?enterprise_id={enterprise_id}", headers=headers)
    assert resp.status_code == 200
    assert isinstance(resp.json(), list)


def test_wesp_compat_components(client: TestClient):
    enterprise_id = make_enterprise(client)
    login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
    token = login.json()["access_token"]
    session = client.post(
        f"/api/v1/enterprise/enterprises/{enterprise_id}/session",
        headers={"Authorization": f"Bearer {token}"},
    )
    token = session.json()["access_token"]
    headers = {"Authorization": f"Bearer {token}"}
    resp = client.get(f"/api/components?enterprise_id={enterprise_id}", headers=headers)
    assert resp.status_code == 200
    assert isinstance(resp.json(), list)


def test_wesp_compat_recipe_includes_ingredients_and_unloading_groups(client: TestClient):
    enterprise_id = make_enterprise(client)
    login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
    token = login.json()["access_token"]
    session = client.post(
        f"/api/v1/enterprise/enterprises/{enterprise_id}/session",
        headers={"Authorization": f"Bearer {token}"},
    )
    token = session.json()["access_token"]
    headers = {"Authorization": f"Bearer {token}"}

    recipe_id = "recipe-compat-1"
    ing_id = "ing-compat-1"
    grp_id = "grp-compat-1"
    apply_catalog_change(
        enterprise_id,
        "recipe",
        recipe_id,
        "upsert",
        {
            "id": recipe_id,
            "name": "Compat Mix",
            "heads_per_trip": 100,
            "mixing_time": 10,
            "trip_percent": 100.0,
        },
        1,
        "r1",
    )
    apply_catalog_change(
        enterprise_id,
        "ingredient",
        ing_id,
        "upsert",
        {
            "id": ing_id,
            "recipe_id": recipe_id,
            "name": "Corn",
            "amount": 12.5,
            "order": 1,
            "dry_matter": 88.0,
        },
        1,
        "i1",
    )
    apply_catalog_change(
        enterprise_id,
        "unloading_group",
        grp_id,
        "upsert",
        {
            "id": grp_id,
            "recipe_id": recipe_id,
            "name": "Barn A",
            "distribution_type": "percent",
            "value": 50.0,
            "weight": 500.0,
            "order": 1,
        },
        1,
        "g1",
    )

    resp = client.get(f"/api/recipes/{recipe_id}?enterprise_id={enterprise_id}", headers=headers)
    assert resp.status_code == 200
    body = resp.json()
    assert body["name"] == "Compat Mix"
    assert len(body.get("ingredients") or []) == 1
    assert body["ingredients"][0]["name"] == "Corn"
    assert len(body.get("unloading_groups") or body.get("unloadingGroups") or []) == 1
    assert body["unloading_groups"][0]["name"] == "Barn A"


def test_wesp_compat_recipe_calculate(client: TestClient):
    resp = client.post(
        "/api/recipes/calculate",
        json={
            "ingredients": [{"weightPerHead": 10, "dryMatter": 88, "component_id": "c1"}],
            "headsCount": 100,
            "tripPercent": 100,
            "unloadingGroups": [{"distributionType": "percent", "value": 50}],
        },
    )
    assert resp.status_code == 200
    body = resp.json()
    assert len(body.get("ingredients") or []) == 1
    assert len(body.get("unloadingGroups") or []) == 1


def test_wesp_compat_recipe_put_persists_unloading_group(client: TestClient):
    enterprise_id = make_enterprise(client)
    login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
    token = login.json()["access_token"]
    session = client.post(
        f"/api/v1/enterprise/enterprises/{enterprise_id}/session",
        headers={"Authorization": f"Bearer {token}"},
    )
    token = session.json()["access_token"]
    headers = {"Authorization": f"Bearer {token}"}

    recipe_id = "recipe-put-1"
    apply_catalog_change(
        enterprise_id,
        "recipe",
        recipe_id,
        "upsert",
        {"id": recipe_id, "name": "Before", "heads_per_trip": 100, "mixing_time": 10, "trip_percent": 100.0},
        1,
        "r1",
    )

    put = client.put(
        f"/api/recipes/{recipe_id}?enterprise_id={enterprise_id}",
        headers=headers,
        json={
            "name": "After",
            "heads_count": 100,
            "mixing_time": 10,
            "trip_percent": 100,
            "dry_matter_locked": False,
            "unloading_link_broken": False,
            "ingredients": [],
            "unloading_groups": [
                {
                    "name": "Group A",
                    "distribution_type": "percent",
                    "value": 100,
                    "weight": 500,
                    "order": 1,
                }
            ],
        },
    )
    assert put.status_code == 200

    got = client.get(f"/api/recipes/{recipe_id}?enterprise_id={enterprise_id}", headers=headers)
    assert got.status_code == 200
    groups = got.json().get("unloading_groups") or []
    assert len(groups) == 1
    assert groups[0]["name"] == "Group A"


def test_wesp_compat_analytics_endpoints(client: TestClient):
    enterprise_id = make_enterprise(client)
    login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
    token = login.json()["access_token"]
    session = client.post(
        f"/api/v1/enterprise/enterprises/{enterprise_id}/session",
        headers={"Authorization": f"Bearer {token}"},
    )
    token = session.json()["access_token"]
    headers = {"Authorization": f"Bearer {token}"}
    params = f"enterprise_id={enterprise_id}&date_from=2026-07-01&date_to=2026-07-15"

    finance = client.get(f"/api/analytics/finance?{params}", headers=headers)
    assert finance.status_code == 200
    assert "overloadRub" in finance.json()

    plan_fact = client.get(f"/api/analytics/plan-fact?{params}", headers=headers)
    assert plan_fact.status_code == 200
    assert plan_fact.json()["items"] == []

    summary = client.get(f"/api/feed-quality/alerts/summary?{params}", headers=headers)
    assert summary.status_code == 200
    assert "total" in summary.json()

    alerts = client.get(f"/api/feed-quality/alerts?{params}", headers=headers)
    assert alerts.status_code == 200
    assert "items" in alerts.json()


def test_wesp_compat_reports_list(client: TestClient):
    from app.modules.zootech.report_apply import apply_report_change

    enterprise_id = make_enterprise(client)
    login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
    token = login.json()["access_token"]
    session = client.post(
        f"/api/v1/enterprise/enterprises/{enterprise_id}/session",
        headers={"Authorization": f"Bearer {token}"},
    )
    token = session.json()["access_token"]
    headers = {"Authorization": f"Bearer {token}"}

    loading_id = "lr-test-1"
    apply_report_change(
        enterprise_id,
        "loading_report",
        loading_id,
        "upsert",
        {
            "recipe_id": "recipe-1",
            "recipe_name": "Test Mix",
            "start_time": datetime.now(UTC).isoformat(),
            "end_time": datetime.now(UTC).isoformat(),
            "total_weight": 1200.0,
            "dispenser_type": "dispenser",
            "components": [{"component_name": "Corn", "actual_weight": 100.0}],
        },
        1,
        "h1",
    )
    apply_report_change(
        enterprise_id,
        "unloading_report",
        "ur-test-1",
        "upsert",
        {
            "loading_report_id": loading_id,
            "start_time": datetime.now(UTC).isoformat(),
            "total_weight": 1200.0,
            "total_unloaded_weight": 1100.0,
            "remaining_weight": 100.0,
        },
        1,
        "u1",
    )

    resp = client.get(f"/api/reports?enterprise_id={enterprise_id}", headers=headers)
    assert resp.status_code == 200
    body = resp.json()
    assert isinstance(body, list)
    assert len(body) == 1
    assert body[0]["recipe_id"] == "recipe-1"
    assert body[0]["unloading_data"]["total_unloaded_weight"] == 1100.0


def test_apply_report_change_update_adds_components(client: TestClient):
    import json
    from app.core.database import session_scope
    from app.modules.zootech.report_apply import apply_report_change
    from app.modules.zootech.report_models import ZootechLoadingReport
    from sqlalchemy import select

    enterprise_id = make_enterprise(client)
    loading_id = "lr-test-components"
    apply_report_change(
        enterprise_id,
        "loading_report",
        loading_id,
        "upsert",
        {
            "recipe_id": "recipe-1",
            "recipe_name": "Test Mix",
            "start_time": datetime.now(UTC).isoformat(),
            "total_weight": 1200.0,
        },
        1,
        "h1",
    )
    apply_report_change(
        enterprise_id,
        "loading_report",
        loading_id,
        "upsert",
        {
            "recipe_id": "recipe-1",
            "recipe_name": "Test Mix",
            "start_time": datetime.now(UTC).isoformat(),
            "total_weight": 1200.0,
            "components": [{"component_name": "Corn", "actual_weight": 100.0, "overload": 5.0}],
        },
        2,
        "h2",
    )
    with session_scope() as db:
        row = db.scalar(
            select(ZootechLoadingReport).where(
                ZootechLoadingReport.enterprise_id == enterprise_id,
                ZootechLoadingReport.id == loading_id,
            )
        )
        assert row is not None
        payload = json.loads(row.payload_json or "{}")
        assert len(payload.get("components") or []) == 1
        assert payload["components"][0]["component_name"] == "Corn"


def test_apply_report_change_feed_alert(client: TestClient):
    from app.core.database import session_scope
    from app.modules.zootech.report_apply import apply_report_change
    from app.modules.zootech.report_models import ZootechFeedAlert
    from sqlalchemy import select

    enterprise_id = make_enterprise(client)
    alert_id = "fa-test-1"
    apply_report_change(
        enterprise_id,
        "feed_alert",
        alert_id,
        "upsert",
        {
            "event_type": "UNDERLOAD",
            "severity": "error",
            "loading_report_id": "lr-1",
            "recipe_id": "recipe-1",
            "recipe_name": "Mix",
            "detail": "Underload detected",
            "deviation_kg": -5.0,
        },
        1,
        "h1",
    )
    with session_scope() as db:
        row = db.scalar(
            select(ZootechFeedAlert).where(
                ZootechFeedAlert.enterprise_id == enterprise_id,
                ZootechFeedAlert.id == alert_id,
            )
        )
        assert row is not None
        assert row.alert_type == "UNDERLOAD"
        assert row.message == "Underload detected"
        assert row.payload_json
