from datetime import datetime

from sqlalchemy import select, text
from sqlalchemy.ext.asyncio import AsyncSession

from src.db.models.form_phase import FormPhase


class FormPhaseRepository:
    def __init__(self, db: AsyncSession):
        self.db = db

    async def get_list(
            self,
            budget_form_id: int,
            sheet: str | None = None,
            phase_code: str | None = None,
    ) -> list[FormPhase]:
        query = select(FormPhase).where(FormPhase.budget_form_id == budget_form_id)
        if sheet is not None:
            query = query.where(FormPhase.sheet == sheet)
        if phase_code is not None:
            query = query.where(FormPhase.phase_code == phase_code)
        return (await self.db.execute(query)).scalars().all()

    async def get(
        self, budget_form_id: int, sheet: str, phase_code: str
    ) -> FormPhase | None:
        query = (
            select(FormPhase)
            .where(FormPhase.budget_form_id == budget_form_id)
            .where(FormPhase.sheet == sheet)
            .where(FormPhase.phase_code == phase_code)
            .limit(1)
        )
        return (await self.db.execute(query)).scalar_one_or_none()

    async def create(
        self,
        budget_form_id: int,
        sheet: str,
        phase_code: str,
        role: str,
        column_keys: list[str],
        opens_at: datetime,
        closes_at: datetime,
    ) -> FormPhase:
        result = await self.db.execute(
            text(
                """
                SELECT
                    (v3.add_form_phase(
                        :budget_form_id,
                        :sheet,
                        :phase_code,
                        :role,
                        :column_keys,
                        CAST(:opens_at AS TIMESTAMP WITHOUT TIME ZONE),
                        CAST(:closes_at AS TIMESTAMP WITHOUT TIME ZONE)
                    )).budget_form_id
                """
            ),
            {
                "budget_form_id": budget_form_id,
                "sheet": sheet,
                "phase_code": phase_code,
                "role": role,
                "column_keys": column_keys,
                "opens_at": opens_at,
                "closes_at": closes_at,
            },
        )
        if result.scalar_one_or_none() is None:
            return None
        return await self.get(budget_form_id, sheet, phase_code)

    async def update(
        self, budget_form_id: int, sheet: str, phase_code: str, data: dict
    ) -> FormPhase | None:
        result = await self.db.execute(
            text(
                """
                SELECT
                    (v3.upd_form_phase(
                        :budget_form_id,
                        :sheet,
                        :phase_code,
                        :role,
                        :column_keys,
                        CAST(:opens_at AS TIMESTAMP WITHOUT TIME ZONE),
                        CAST(:closes_at AS TIMESTAMP WITHOUT TIME ZONE)
                    )).budget_form_id
                """
            ),
            {
                "budget_form_id": budget_form_id,
                "sheet": sheet,
                "phase_code": phase_code,
                "role": data.get("role"),
                "column_keys": data.get("column_keys"),
                "opens_at": data.get("opens_at"),
                "closes_at": data.get("closes_at"),
            },
        )
        if result.scalar_one_or_none() is None:
            return None
        return await self.get(budget_form_id, sheet, phase_code)

    async def delete(
        self, budget_form_id: int, sheet: str, phase_code: str
    ) -> bool:
        result = await self.db.execute(
            text(
                "SELECT v3.del_form_phase(:budget_form_id, :sheet, :phase_code)"
            ),
            {
                "budget_form_id": budget_form_id,
                "sheet": sheet,
                "phase_code": phase_code,
            },
        )
        deleted = result.scalar_one_or_none()
        return bool(deleted)
