"""Realtime domain — data access layer."""
from __future__ import annotations

from typing import Optional
from uuid import UUID, uuid4

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

from src.domain.realtime.models import ProjectRealtimeChannel, ProjectRealtimeConfig


class ProjectRealtimeConfigRepository:
    def __init__(self, db: AsyncSession) -> None:
        self._db = db

    async def get_by_project(self, project_id: UUID) -> Optional[ProjectRealtimeConfig]:
        result = await self._db.execute(
            select(ProjectRealtimeConfig).where(
                ProjectRealtimeConfig.project_id == project_id
            )
        )
        return result.scalar_one_or_none()

    async def create(self, project_id: UUID, **fields) -> ProjectRealtimeConfig:
        row = ProjectRealtimeConfig(id=uuid4(), project_id=project_id, **fields)
        self._db.add(row)
        await self._db.flush()
        return row

    async def update(self, row: ProjectRealtimeConfig, **fields) -> ProjectRealtimeConfig:
        for k, v in fields.items():
            setattr(row, k, v)
        await self._db.flush()
        return row


class ProjectRealtimeChannelRepository:
    def __init__(self, db: AsyncSession) -> None:
        self._db = db

    async def list_for_project(self, project_id: UUID) -> list[ProjectRealtimeChannel]:
        result = await self._db.execute(
            select(ProjectRealtimeChannel)
            .where(ProjectRealtimeChannel.project_id == project_id)
            .order_by(ProjectRealtimeChannel.name)
        )
        return list(result.scalars().all())

    async def get_by_name(
        self, project_id: UUID, name: str
    ) -> Optional[ProjectRealtimeChannel]:
        result = await self._db.execute(
            select(ProjectRealtimeChannel).where(
                ProjectRealtimeChannel.project_id == project_id,
                ProjectRealtimeChannel.name == name,
            )
        )
        return result.scalar_one_or_none()

    async def count_for_project(self, project_id: UUID) -> int:
        from sqlalchemy import func
        result = await self._db.execute(
            select(func.count()).where(
                ProjectRealtimeChannel.project_id == project_id
            )
        )
        return result.scalar_one()

    async def create(
        self, project_id: UUID, name: str, access_policy: str, rls_filter: bool
    ) -> ProjectRealtimeChannel:
        row = ProjectRealtimeChannel(
            id=uuid4(),
            project_id=project_id,
            name=name,
            access_policy=access_policy,
            rls_filter=rls_filter,
        )
        self._db.add(row)
        await self._db.flush()
        return row

    async def update(
        self, row: ProjectRealtimeChannel, **fields
    ) -> ProjectRealtimeChannel:
        for k, v in fields.items():
            setattr(row, k, v)
        await self._db.flush()
        return row

    async def delete(self, row: ProjectRealtimeChannel) -> None:
        await self._db.delete(row)
        await self._db.flush()
