from datetime import datetime
from types import SimpleNamespace
from uuid import UUID

from dsg_core.core.model import Field, Model
from dsg_core.services.reports.reportService import ReportService


class ReportQuery(Model):
    item_type_id: UUID
    filters: list = Field(default_factory=list)
    order_by: list = Field(default_factory=list)
    versions: list = Field(default_factory=list)
    include_history: bool = False
    valid_at: datetime | None = None


def _build_query(valid_at: str) -> ReportQuery:
    return ReportQuery.model_validate(
        {
            "filters": [],
            "orderBy": [],
            "validAt": valid_at,
            "versions": [],
            "itemTypeId": "4b7acb60-ef3d-4374-9d91-79c3843a7a7a",
            "includeHistory": False,
        }
    )


def test_build_query_payload_normalizes_equivalent_utc_valid_at_values() -> None:
    payload_with_offset = ReportService.build_query_payload(
        _build_query("2026-04-28T12:01:47.926236+00:00"),
        include_alias=False,
        output_format="csv",
    )
    payload_with_zulu = ReportService.build_query_payload(
        _build_query("2026-04-28T12:01:47.926236Z"),
        include_alias=False,
        output_format="csv",
    )

    assert payload_with_offset == payload_with_zulu
    assert payload_with_offset["query"]["validAt"] == "2026-04-28T12:01:47.926236Z"


def test_build_report_request_id_normalizes_equivalent_utc_valid_at_values() -> None:
    payload_with_offset = ReportService.build_query_payload(
        _build_query("2026-04-28T12:01:47.926236+00:00"),
        include_alias=False,
        output_format="csv",
    )
    payload_with_zulu = ReportService.build_query_payload(
        _build_query("2026-04-28T12:01:47.926236Z"),
        include_alias=False,
        output_format="csv",
    )

    assert ReportService.build_report_request_id(
        payload_with_offset
    ) == ReportService.build_report_request_id(payload_with_zulu)


def test_build_report_request_id_normalizes_filter_order() -> None:
    payload_a = ReportQuery.model_validate(
        {
            "filters": [
                {"field": "code", "operator": "=", "value": "A"},
                {"field": "status", "operand": "=", "value": "active"},
            ],
            "orderBy": [],
            "validAt": "2026-04-28T12:01:47.926236Z",
            "versions": [],
            "itemTypeId": "4b7acb60-ef3d-4374-9d91-79c3843a7a7a",
            "includeHistory": False,
        }
    )
    payload_b = ReportQuery.model_validate(
        {
            "filters": [
                {"field": "status", "operand": "=", "value": "active"},
                {"field": "code", "op": "=", "value": "A"},
            ],
            "orderBy": [],
            "validAt": "2026-04-28T12:01:47.926236+00:00",
            "versions": [],
            "itemTypeId": "4b7acb60-ef3d-4374-9d91-79c3843a7a7a",
            "includeHistory": False,
        }
    )

    normalized_payload_a = ReportService.build_query_payload(
        payload_a, include_alias=False, output_format="csv"
    )
    normalized_payload_b = ReportService.build_query_payload(
        payload_b, include_alias=False, output_format="csv"
    )

    assert normalized_payload_a == normalized_payload_b
    assert ReportService.build_report_request_id(
        normalized_payload_a
    ) == ReportService.build_report_request_id(normalized_payload_b)


def test_build_report_request_id_normalizes_nested_filter_order() -> None:
    payload_a = ReportQuery.model_validate(
        {
            "filters": [
                {
                    "or": [
                        {"field": "status", "operand": "=", "value": "draft"},
                        {"field": "status", "operand": "=", "value": "active"},
                    ]
                },
                {"field": "code", "operand": "=", "value": "A"},
            ],
            "orderBy": [],
            "validAt": "2026-04-28T12:01:47.926236Z",
            "versions": [],
            "itemTypeId": "4b7acb60-ef3d-4374-9d91-79c3843a7a7a",
            "includeHistory": False,
        }
    )
    payload_b = ReportQuery.model_validate(
        {
            "filters": [
                {"field": "code", "operand": "=", "value": "A"},
                {
                    "or": [
                        {"field": "status", "operand": "=", "value": "active"},
                        {"field": "status", "operand": "=", "value": "draft"},
                    ]
                },
            ],
            "orderBy": [],
            "validAt": "2026-04-28T12:01:47.926236Z",
            "versions": [],
            "itemTypeId": "4b7acb60-ef3d-4374-9d91-79c3843a7a7a",
            "includeHistory": False,
        }
    )

    normalized_payload_a = ReportService.build_query_payload(
        payload_a, include_alias=False, output_format="csv"
    )
    normalized_payload_b = ReportService.build_query_payload(
        payload_b, include_alias=False, output_format="csv"
    )

    assert normalized_payload_a == normalized_payload_b
    assert ReportService.build_report_request_id(
        normalized_payload_a
    ) == ReportService.build_report_request_id(normalized_payload_b)


def test_get_cached_report_uses_primary_key_lookup_only(monkeypatch) -> None:
    report_entry = SimpleNamespace(
        query_id="43bc7e50-eb18-5e4c-a6b7-e2078e135d6e",
        s3_bucket="bucket",
        s3_key="reports/file.xlsx",
    )

    class SessionSpy:
        def __init__(self) -> None:
            self.get_calls: list[tuple[object, object]] = []

        def get(self, model, query_id):
            self.get_calls.append((model, query_id))
            return report_entry

        def exec(self, *args, **kwargs):
            raise AssertionError(
                "Unexpected query execution outside primary-key lookup"
            )

    session = SessionSpy()
    monkeypatch.setattr(
        "dsg_core.services.reports.reportService.object_exists",
        lambda *, key, bucket: key == "reports/file.xlsx" and bucket == "bucket",
    )

    cached_report = ReportService.get_cached_report(
        "43bc7e50-eb18-5e4c-a6b7-e2078e135d6e",
        session=session,
    )

    assert cached_report is report_entry
    assert len(session.get_calls) == 1
