from collections.abc import Sequence
from typing import Any

import uuid

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

from src.domain.entities import ConnectorVersionEntity
from src.domain.interfaces import IConnectorVersionRepository
from src.infrastructure.database.models import ConnectorVersionModel


def _model_to_entity(m: ConnectorVersionModel) -> ConnectorVersionEntity:
    return ConnectorVersionEntity(
        id=m.id,
        connector_id=m.connector_id,
        connector_type=m.connector_type,
        version=m.version,
        changelog=m.changelog,
        download_url=m.download_url,
        checksum=m.checksum,
        is_latest=m.is_latest,
        is_required=m.is_required,
        released_at=m.released_at,
        created_at=m.created_at,
    )


class ConnectorVersionRepository(IConnectorVersionRepository):
    def __init__(self, session: AsyncSession) -> None:
        self._session = session

    async def get_latest(self, connector_type: str) -> ConnectorVersionEntity | None:
        stmt = (
            select(ConnectorVersionModel)
            .where(ConnectorVersionModel.connector_type == connector_type, ConnectorVersionModel.is_latest == True)  # noqa: E712
            .order_by(ConnectorVersionModel.released_at.desc())
            .limit(1)
        )
        result = await self._session.execute(stmt)
        model = result.scalar_one_or_none()
        return _model_to_entity(model) if model else None

    async def list_versions(
        self,
        *,
        connector_type: str | None = None,
        offset: int = 0,
        limit: int = 50,
    ) -> tuple[Sequence[ConnectorVersionEntity], int]:
        filters: list[Any] = []
        if connector_type:
            filters.append(ConnectorVersionModel.connector_type == connector_type)

        count_stmt = select(func.count()).select_from(ConnectorVersionModel)
        if filters:
            count_stmt = count_stmt.where(*filters)
        total = (await self._session.execute(count_stmt)).scalar() or 0

        stmt = select(ConnectorVersionModel).order_by(ConnectorVersionModel.released_at.desc()).offset(offset).limit(limit)
        if filters:
            stmt = stmt.where(*filters)
        result = await self._session.execute(stmt)
        models = result.scalars().all()
        return [_model_to_entity(m) for m in models], total

    async def create(self, entity: ConnectorVersionEntity) -> ConnectorVersionEntity:
        model = ConnectorVersionModel(
            connector_id=entity.connector_id or uuid.uuid4(),
            connector_type=entity.connector_type if isinstance(entity.connector_type, str) else entity.connector_type.value,
            version=entity.version,
            changelog=entity.changelog,
            download_url=entity.download_url,
            checksum=entity.checksum,
            is_latest=entity.is_latest,
            is_required=entity.is_required,
            released_at=entity.released_at,
        )
        self._session.add(model)
        await self._session.flush()
        return _model_to_entity(model)
