from datetime import datetime

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

from src.db.models.form3_phase import Form3Phase


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

    async def get_list(
            self,
            report_id: int | list[int],
            phase_code: str | None = None,
    ) -> list[Form3Phase]:
        if isinstance(report_id, int):
            query = select(Form3Phase).where(Form3Phase.rf_project_report_id == report_id)
        else:
            query = select(Form3Phase).where(Form3Phase.rf_project_report_id.in_(report_id))
        if phase_code is not None:
            query = query.where(Form3Phase.phase_code == phase_code)
        return (await self.db.execute(query)).scalars().all()

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

    async def create(
        self,
        report_id: int,
        phase_code: str,
        role: str,
        column_keys: list[str],
        opens_at: datetime,
        closes_at: datetime,
    ) -> Form3Phase:
        result = await self.db.execute(
            text(
                """
                SELECT
                    (v3.add_form3_phase(
                        :report_id,
                        :phase_code,
                        :role,
                        :column_keys,
                        CAST(:opens_at AS TIMESTAMP WITHOUT TIME ZONE),
                        CAST(:closes_at AS TIMESTAMP WITHOUT TIME ZONE)
                    )).rf_project_report_id
                """
            ),
            {
                "report_id": report_id,
                "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(report_id, phase_code)

    async def update(
        self, report_id: int, phase_code: str, data: dict
    ) -> Form3Phase | None:
        result = await self.db.execute(
            text(
                """
                SELECT
                    (v3.upd_form3_phase(
                        :report_id,
                        :phase_code,
                        :role,
                        :column_keys,
                        CAST(:opens_at AS TIMESTAMP WITHOUT TIME ZONE),
                        CAST(:closes_at AS TIMESTAMP WITHOUT TIME ZONE)
                    )).rf_project_report_id
                """
            ),
            {
                "report_id": report_id,
                "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(report_id, phase_code)

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