from typing import Optional, List
from datetime import datetime
from sqlalchemy import select, delete, desc, update
from src.models.app_updates import Versao
from sqlalchemy.ext.asyncio import AsyncSession
from src.schemas.app_updates import VersaoCreate, VersaoUpdate


class VersaoCRUD:
    async def get_by_id(
        self,
            db: AsyncSession,
            versao_id: int) -> Optional[Versao]:
        result = await db.execute(select(Versao).where(Versao.id == versao_id))
        return result.scalar_one_or_none()

    async def get_by_version_build(
        self,
        db: AsyncSession,
        versao: str,
        build: int
    ) -> Optional[Versao]:
        """Busca uma versão específica pelo número de versão e build"""
        result = await db.execute(
            select(Versao).where(
                Versao.versao == versao,
                Versao.build == build
            )
        )
        return result.scalar_one_or_none()

    async def get_latest_version(self, db: AsyncSession) -> Optional[Versao]:
        """Busca a versão mais recente ativa"""
        result = await db.execute(
            select(Versao)
            .where(Versao.ativo is True)
            .order_by(desc(Versao.build))
            .limit(1)
        )
        return result.scalar_one_or_none()

    async def list(
        self,
        db: AsyncSession,
        *,
        ativo: Optional[bool] = None,
        limit: int = 100,
    ) -> List[Versao]:
        stmt = select(Versao).order_by(desc(Versao.build))

        if ativo is not None:
            stmt = stmt.where(Versao.ativo == ativo)

        stmt = stmt.limit(limit)
        result = await db.execute(stmt)
        return list(result.scalars().all())

    async def create(self, db: AsyncSession, payload: VersaoCreate) -> Versao:
        obj = Versao(
            versao=payload.versao,
            build=payload.build,
            nomeArquivo=payload.nomeArquivo,
            caminhoArquivo=payload.caminhoArquivo,
            hashSha256=payload.hashSha256,
            tamanhoBytes=payload.tamanhoBytes,
            changelog=payload.changelog,
            atualizacaoObrigatoria=payload.atualizacaoObrigatoria,
            ativo=payload.ativo,
            dataRelease=datetime.now(),
        )
        db.add(obj)
        await db.commit()
        await db.refresh(obj)
        return obj

    async def update(
        self,
        db: AsyncSession,
        versao_id: int,
        payload: VersaoUpdate,
    ) -> Optional[Versao]:
        obj = await self.get_by_id(db, versao_id)
        if not obj:
            return None

        update_data = payload.model_dump(exclude_unset=True)
        for field, value in update_data.items():
            setattr(obj, field, value)

        await db.commit()
        await db.refresh(obj)
        return obj

    async def delete(self, db: AsyncSession, versao_id: int) -> bool:
        obj = await self.get_by_id(db, versao_id)
        if not obj:
            return False

        await db.execute(delete(Versao).where(Versao.id == versao_id))
        await db.commit()
        return True

    async def deactivate_old_versions(
        self,
        db: AsyncSession,
        except_id: Optional[int] = None
    ) -> int:
        """Desativa versões antigas, opcionalmente exceto uma específica"""
        stmt = update(Versao).where(Versao.ativo).values(ativo=False)

        if except_id:
            stmt = stmt.where(Versao.id != except_id)

        result = await db.execute(stmt)
        await db.commit()
        return result.rowcount
