from backend.app.db.models.condition import PropertyConditionSurveyModel
from backend.condition.domain.property_condition_survey import PropertyConditionSurvey


class CustomAsserts:
    def assert_property_condition_surveys_equal(
        actual: PropertyConditionSurvey,
        expected: PropertyConditionSurvey,
    ) -> bool:
        assert actual.uprn == expected.uprn, "UPRN differs"
        assert actual.source == expected.source, "Source differs"
        assert actual.date == expected.date, "Date differs"

        assert len(actual.elements) == len(expected.elements), (
            f"Expected {len(expected.elements)} elements, "
            f"got {len(actual.elements)}"
        )

        for i, (actual_element, expected_element) in enumerate(
            zip(actual.elements, expected.elements)
        ):
            assert actual_element.element_type == expected_element.element_type, (
                f"Element[{i}] type differs: "
                f"{actual_element.element_type} != {expected_element.element_type}"
            )
            assert (
                actual_element.element_instance == expected_element.element_instance
            ), (
                f"Element[{i}] instance differs: "
                f"{actual_element.element_instance} != {expected_element.element_instance}"
            )

            assert len(actual_element.aspect_conditions) == len(
                expected_element.aspect_conditions
            ), f"Element[{i}] aspect count differs"

            for j, (actual_aspect, expected_aspect) in enumerate(
                zip(
                    actual_element.aspect_conditions,
                    expected_element.aspect_conditions,
                )
            ):
                prefix = f"Element[{i}].Aspect[{j}]"

                assert actual_aspect.aspect_type == expected_aspect.aspect_type, (
                    f"{prefix}.aspect_type differs: "
                    f"{actual_aspect.aspect_type} != {expected_aspect.aspect_type}"
                )
                assert (
                    actual_aspect.aspect_instance == expected_aspect.aspect_instance
                ), (
                    f"{prefix}.aspect_instance differs: "
                    f"{actual_aspect.aspect_instance} != {expected_aspect.aspect_instance}"
                )
                assert actual_aspect.value == expected_aspect.value, (
                    f"{prefix}.value differs: "
                    f"{actual_aspect.value} != {expected_aspect.value}"
                )
                assert actual_aspect.quantity == expected_aspect.quantity, (
                    f"{prefix}.quantity differs: "
                    f"{actual_aspect.quantity} != {expected_aspect.quantity}"
                )
                assert actual_aspect.install_date == expected_aspect.install_date, (
                    f"{prefix}.install_date differs: "
                    f"{actual_aspect.install_date} != {expected_aspect.install_date}"
                )
                assert actual_aspect.renewal_year == expected_aspect.renewal_year, (
                    f"{prefix}.renewal_year differs: "
                    f"{actual_aspect.renewal_year} != {expected_aspect.renewal_year}"
                )
                assert actual_aspect.comments == expected_aspect.comments, (
                    f"{prefix}.comments differs: "
                    f"{actual_aspect.comments} != {expected_aspect.comments}"
                )
        return True

    def assert_property_condition_survey_model_matches_expected(
        actual_model: PropertyConditionSurveyModel,
        expected: dict,
    ) -> None:
        assert actual_model.uprn == expected["uprn"], "UPRN differs"
        assert actual_model.date == expected["date"], "Date differs"
        assert actual_model.source == expected["source"], "Source differs"

        assert len(actual_model.elements) == len(expected["elements"]), (
            f"Expected {len(expected['elements'])} elements, "
            f"got {len(actual_model.elements)}"
        )

        for i, (actual_element, expected_element) in enumerate(
            zip(actual_model.elements, expected["elements"])
        ):
            assert (
                actual_element.element_type == expected_element["element_type"]
            ), f"Element[{i}].element_type differs"
            assert (
                actual_element.element_instance == expected_element["element_instance"]
            ), f"Element[{i}].element_instance differs"

            assert len(actual_element.aspect_conditions) == len(
                expected_element["aspects"]
            ), f"Element[{i}] aspect count differs"

            for j, (actual_aspect, expected_aspect) in enumerate(
                zip(actual_element.aspect_conditions, expected_element["aspects"])
            ):
                prefix = f"Element[{i}].Aspect[{j}]"

                for key, value in expected_aspect.items():
                    assert getattr(actual_aspect, key) == value, (
                        f"{prefix}.{key} differs: "
                        f"{getattr(actual_aspect, key)} != {value}"
                    )
