import json
from pathlib import Path
from typing import Any

import pytest

from datatypes.magicplan.api.response import MagicPlanPlan, PlansListResponse

FIXTURE_DIR = Path(__file__).parents[4] / "backend" / "magic_plan"
PLAN_ID = "a7285ed1-878d-47eb-8aa6-85ef9e187516"


@pytest.fixture(scope="module")
def raw_data() -> dict[str, Any]:
    payload = json.loads(
        (FIXTURE_DIR / "magicplan_api_plan_response_example.json").read_text()
    )
    return payload["data"]


@pytest.fixture(scope="module")
def mp(raw_data: dict[str, Any]) -> MagicPlanPlan:
    return MagicPlanPlan.model_validate(raw_data)


def test_model_validate_does_not_raise(raw_data: dict[str, Any]):
    # act
    MagicPlanPlan.model_validate(raw_data)


def test_plan_id(mp: MagicPlanPlan):
    # assert
    assert mp.plan.id == PLAN_ID


def test_url_3d_alias(mp: MagicPlanPlan):
    # assert
    assert mp.plan.url_3d is not None
    assert mp.plan.url_3d.startswith("http")


def test_floor_count(mp: MagicPlanPlan):
    # assert
    assert len(mp.plan_detail.plan.floors) == 2


def test_first_room_name(mp: MagicPlanPlan):
    # assert
    assert mp.plan_detail.plan.floors[0].rooms[0].name == "Kitchen"


def test_room_area_is_float(mp: MagicPlanPlan):
    # arrange
    room = mp.plan_detail.plan.floors[0].rooms[0]
    # assert
    assert isinstance(room.area, float)


def test_wall_item_symbol_id(mp: MagicPlanPlan):
    # arrange
    room = mp.plan_detail.plan.floors[0].rooms[0]
    # assert
    assert room.wall_items[0].symbol.id != ""


def test_field_value_array(mp: MagicPlanPlan):
    # arrange
    room = mp.plan_detail.plan.floors[0].rooms[0]
    array_field = next(f for f in room.displayable_fields if f.value.is_array)
    # assert
    assert isinstance(array_field.value.value, list)


def test_field_value_scalar(mp: MagicPlanPlan):
    # arrange
    room = mp.plan_detail.plan.floors[0].rooms[0]
    scalar_field = next(f for f in room.displayable_fields if not f.value.is_array)
    # assert
    assert isinstance(scalar_field.value.value, str)


def test_extra_fields_ignored(raw_data: dict[str, Any]):
    # arrange
    data_with_extra = {**raw_data, "unknown_future_field": "whatever"}
    # act
    MagicPlanPlan.model_validate(data_with_extra)


# --- PlansListResponse ---


@pytest.fixture(scope="module")
def plans_raw_data() -> dict[str, Any]:
    payload = json.loads(
        (FIXTURE_DIR / "magicplan_api_plans_response_example.json").read_text()
    )
    return payload["data"]


@pytest.fixture(scope="module")
def plans_response(plans_raw_data: dict[str, Any]) -> PlansListResponse:
    return PlansListResponse.model_validate(plans_raw_data)


def test_plans_list_model_validate_does_not_raise(
    plans_raw_data: dict[str, Any],
) -> None:
    # act
    PlansListResponse.model_validate(plans_raw_data)


def test_plans_list_count(plans_response: PlansListResponse) -> None:
    # assert
    assert len(plans_response.plans) == 1


def test_plans_list_first_plan_id(plans_response: PlansListResponse) -> None:
    # assert
    assert plans_response.plans[0].id == "9f9889ff-793e-4e9a-a6f0-e22f5b0f5365"


def test_plans_list_paging_page(plans_response: PlansListResponse) -> None:
    # assert
    assert plans_response.paging.page == 1


def test_plans_list_paging_next_page_is_false(
    plans_response: PlansListResponse,
) -> None:
    # assert
    assert plans_response.paging.next_page is False


def test_plans_list_paging_count(plans_response: PlansListResponse) -> None:
    # assert
    assert plans_response.paging.count == 1


def test_plans_list_unknown_keys_ignored(plans_raw_data: dict[str, Any]) -> None:
    # arrange
    data_with_extra = {**plans_raw_data, "unknown_future_field": "whatever"}
    # act
    PlansListResponse.model_validate(data_with_extra)
