"""Destination channel persistence."""

from __future__ import annotations

from sqlalchemy import func, select

from app.database.base import utcnow
from app.database.models import PostDestination, PublishChannel
from app.database.repositories.base import BaseRepository


class ChannelRepository(BaseRepository):
    async def get(self, channel_id: int) -> PublishChannel | None:
        async with self.db.session() as session:
            return await session.get(PublishChannel, channel_id)

    async def get_by_chat_id(self, chat_id: int) -> PublishChannel | None:
        async with self.db.session() as session:
            return await session.scalar(
                select(PublishChannel).where(PublishChannel.chat_id == chat_id)
            )

    async def list(self, *, active_only: bool = False) -> list[PublishChannel]:
        async with self.db.session() as session:
            statement = select(PublishChannel).order_by(PublishChannel.created_at)
            if active_only:
                statement = statement.where(PublishChannel.is_active.is_(True))
            return list(await session.scalars(statement))

    async def default(self) -> PublishChannel | None:
        async with self.db.session() as session:
            return await session.scalar(
                select(PublishChannel).where(
                    PublishChannel.is_default.is_(True),
                    PublishChannel.is_active.is_(True),
                )
            )

    async def add(
        self,
        chat_id: int,
        *,
        title: str | None,
        username: str | None,
        chat_type: str,
        added_by: int | None,
        can_post: bool | None = None,
        error: str | None = None,
    ) -> tuple[PublishChannel, bool]:
        async with self.db.session() as session:
            channel = await session.scalar(
                select(PublishChannel).where(PublishChannel.chat_id == chat_id)
            )
            if channel is not None:
                channel.is_active = True
                channel.title = title or channel.title
                channel.username = username or channel.username
                channel.can_post = can_post
                channel.last_checked_at = utcnow()
                channel.last_error = error
                return channel, False
            channel = PublishChannel(
                chat_id=chat_id,
                title=title,
                username=username,
                chat_type=chat_type,
                is_active=True,
                can_post=can_post,
                last_checked_at=utcnow(),
                last_error=error,
                added_by=added_by,
            )
            session.add(channel)
            await session.flush()
            return channel, True

    async def update_access(
        self,
        channel_id: int,
        *,
        can_post: bool,
        error: str | None,
        title: str | None = None,
        username: str | None = None,
    ) -> None:
        async with self.db.session() as session:
            channel = await session.get(PublishChannel, channel_id)
            if channel is None:
                return
            channel.can_post = can_post
            channel.last_checked_at = utcnow()
            channel.last_error = error
            if title:
                channel.title = title
            if username:
                channel.username = username

    async def set_default(self, channel_id: int) -> bool:
        async with self.db.session() as session:
            channel = await session.get(PublishChannel, channel_id)
            if channel is None or not channel.is_active:
                return False
            channels = (await session.scalars(select(PublishChannel))).all()
            for item in channels:
                item.is_default = item.id == channel_id
            return True

    async def set_active(self, channel_id: int, active: bool) -> bool:
        async with self.db.session() as session:
            channel = await session.get(PublishChannel, channel_id)
            if channel is None:
                return False
            channel.is_active = active
            if not active:
                channel.is_default = False
            return True

    async def has_destinations(self, channel_id: int) -> bool:
        async with self.db.session() as session:
            count = await session.scalar(
                select(func.count(PostDestination.id)).where(
                    PostDestination.channel_id == channel_id
                )
            )
            return bool(count)

    async def remove(self, channel_id: int) -> bool:
        async with self.db.session() as session:
            channel = await session.get(PublishChannel, channel_id)
            if channel is None:
                return False
            await session.delete(channel)
            return True
