import io
from types import SimpleNamespace
from unittest.mock import AsyncMock, call

import pytest

from src.db.models.form_type import FormTypeEnum
from src.domain.schemas import DirectionSchemaEnum
from src.services.export_service import ExportService


def _build_form(
    *,
    form_type_code: FormTypeEnum = FormTypeEnum.FORM_1,
    sheet_list: list[str] | None = None,
    section_list: list[str] | None = None,
    sheet_list_with_directions: list[dict] | None = None,
) -> SimpleNamespace:
    return SimpleNamespace(
        id=1,
        year=2026,
        form_type_code=form_type_code.value,
        org_unit_id=10,
        org_unit=SimpleNamespace(title="Org"),
        form_type=SimpleNamespace(
            code=form_type_code,
            sheet_list=sheet_list or ["AHR", "SMETA"],
            section_list=section_list or ["plan", "q1"],
            sheet_list_with_directions=sheet_list_with_directions or [
                {
                    "sheet_name": "AHR",
                    "direction": "Support",
                },
                {
                    "sheet_name": "AHR",
                    "direction": "Development",

                },
                {
                    "sheet_name": "SMETA",
                    "direction": None,

                },
            ],
        ),
    )


@pytest.mark.asyncio
async def test_export_sheet_rejects_direction_for_unsupported_sheet():
    service = ExportService(AsyncMock())
    service.budget_form_service.get = AsyncMock(
        return_value=_build_form(sheet_list=["SMETA"])
    )
    service.sheet_service.get = AsyncMock(return_value=[])

    with pytest.raises(ValueError, match="direction допустим только"):
        await service.export_form_to_xlsx(
            form_id=1,
            current_user=SimpleNamespace(),
            sheet="SMETA",
            direction=DirectionSchemaEnum.SUPPORT.value,
        )


@pytest.mark.asyncio
async def test_export_sheet_rejects_sections_for_unsupported_sheet():
    service = ExportService(AsyncMock())
    service.budget_form_service.get = AsyncMock(
        return_value=_build_form(
            sheet_list=["SMETA"],
            sheet_list_with_directions=[
                {
                    "sheet_name": "SMETA",
                    "direction": None,
                }
            ],
        )
    )
    service.sheet_service.get = AsyncMock(return_value=[])

    with pytest.raises(ValueError, match="sections не поддерживается"):
        await service.export_form_to_xlsx(
            form_id=1,
            current_user=SimpleNamespace(),
            sheet="SMETA",
            sections=["q1"],
        )


@pytest.mark.asyncio
async def test_export_full_form_ignores_non_applicable_params_for_other_sheets():
    service = ExportService(AsyncMock())
    service.budget_form_service.get = AsyncMock(return_value=_build_form())
    service.sheet_service.get = AsyncMock(return_value=[])

    stream, filename = await service.export_form_to_xlsx(
        form_id=1,
        current_user=SimpleNamespace(),
        direction=DirectionSchemaEnum.SUPPORT.value,
        sections=["q1"],
        ignore_non_applicable_query_params=True,
    )

    assert stream.getbuffer().nbytes > 0
    assert filename.endswith(".xlsx")
    assert service.sheet_service.get.await_args_list == [
        call(
            form_id=1,
            sheet="AHR",
            direction=DirectionSchemaEnum.SUPPORT.value,
            sections=["q1"],
        ),
        call(
            form_id=1,
            sheet="SMETA",
            direction=None,
            sections=None,
        ),
    ]


@pytest.mark.asyncio
async def test_export_form_payload_forwards_ignore_flag():
    service = ExportService(AsyncMock())
    service.export_form_to_xlsx = AsyncMock(return_value=(io.BytesIO(), "demo.xlsx"))

    await service.export_form_payload(
        form_id=1,
        current_user=SimpleNamespace(),
        ignore_non_applicable_query_params=True,
    )

    assert service.export_form_to_xlsx.await_count == 1
    assert (
        service.export_form_to_xlsx.await_args.kwargs[
            "ignore_non_applicable_query_params"
        ]
        is True
    )
