"""SQL implementation of PageConfig service methods.

Extracted from blog/bp/data/routes.py and blog/bp/actions/routes.py
to enable sx defquery/defaction conversion.
"""
from __future__ import annotations

from typing import Any

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm.attributes import flag_modified

from shared.models.page_config import PageConfig


def _to_dict(pc: PageConfig) -> dict[str, Any]:
    return {
        "id": pc.id,
        "container_type": pc.container_type,
        "container_id": pc.container_id,
        "features": pc.features or {},
        "sumup_merchant_code": pc.sumup_merchant_code,
        "sumup_api_key": pc.sumup_api_key,
        "sumup_checkout_prefix": pc.sumup_checkout_prefix,
    }


class SqlPageConfigService:

    async def ensure(
        self, session: AsyncSession, *,
        container_type: str = "page", container_id: int,
    ) -> dict[str, Any]:
        """Get or create a PageConfig. Returns minimal dict with id."""
        row = (await session.execute(
            select(PageConfig).where(
                PageConfig.container_type == container_type,
                PageConfig.container_id == container_id,
            )
        )).scalar_one_or_none()

        if row is None:
            row = PageConfig(
                container_type=container_type,
                container_id=container_id,
                features={},
            )
            session.add(row)
            await session.flush()

        return {
            "id": row.id,
            "container_type": row.container_type,
            "container_id": row.container_id,
        }

    async def get_by_container(
        self, session: AsyncSession, *,
        container_type: str = "page", container_id: int,
    ) -> dict[str, Any] | None:
        pc = (await session.execute(
            select(PageConfig).where(
                PageConfig.container_type == container_type,
                PageConfig.container_id == container_id,
            )
        )).scalar_one_or_none()
        return _to_dict(pc) if pc else None

    async def get_by_id(
        self, session: AsyncSession, *, id: int,
    ) -> dict[str, Any] | None:
        pc = await session.get(PageConfig, id)
        return _to_dict(pc) if pc else None

    async def get_batch(
        self, session: AsyncSession, *,
        container_type: str = "page", ids: list[int],
    ) -> list[dict[str, Any]]:
        if not ids:
            return []
        result = await session.execute(
            select(PageConfig).where(
                PageConfig.container_type == container_type,
                PageConfig.container_id.in_(ids),
            )
        )
        return [_to_dict(pc) for pc in result.scalars().all()]

    async def update(
        self, session: AsyncSession, *,
        container_type: str = "page", container_id: int,
        features: dict | None = None,
        sumup_merchant_code: str | None = None,
        sumup_checkout_prefix: str | None = None,
        sumup_api_key: str | None = None,
    ) -> dict[str, Any]:
        pc = (await session.execute(
            select(PageConfig).where(
                PageConfig.container_type == container_type,
                PageConfig.container_id == container_id,
            )
        )).scalar_one_or_none()

        if pc is None:
            pc = PageConfig(
                container_type=container_type,
                container_id=container_id,
                features=features or {},
            )
            session.add(pc)
            await session.flush()

        if features is not None:
            merged = dict(pc.features or {})
            for key, val in features.items():
                if isinstance(val, bool):
                    merged[key] = val
                elif val in ("true", "1", "on"):
                    merged[key] = True
                elif val in ("false", "0", "off", None):
                    merged[key] = False
            pc.features = merged
            flag_modified(pc, "features")

        if sumup_merchant_code is not None:
            pc.sumup_merchant_code = sumup_merchant_code or None
        if sumup_checkout_prefix is not None:
            pc.sumup_checkout_prefix = sumup_checkout_prefix or None
        if sumup_api_key is not None:
            pc.sumup_api_key = sumup_api_key or None

        await session.flush()

        result = _to_dict(pc)
        result["sumup_configured"] = bool(pc.sumup_api_key)
        return result
