"""Worker Fleet 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.fleet.models import (
    WorkerFleetEvent,
    WorkerFleetRegistry,
    WorkerScalingConfig,
)


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

    async def list_all(self) -> list[WorkerFleetRegistry]:
        result = await self._db.execute(
            select(WorkerFleetRegistry).order_by(
                WorkerFleetRegistry.worker_name, WorkerFleetRegistry.instance_id
            )
        )
        return list(result.scalars().all())

    async def list_for_worker(self, worker_name: str) -> list[WorkerFleetRegistry]:
        result = await self._db.execute(
            select(WorkerFleetRegistry)
            .where(WorkerFleetRegistry.worker_name == worker_name)
            .order_by(WorkerFleetRegistry.instance_id)
        )
        return list(result.scalars().all())

    async def get_instance(
        self, worker_name: str, instance_id: str
    ) -> Optional[WorkerFleetRegistry]:
        result = await self._db.execute(
            select(WorkerFleetRegistry).where(
                WorkerFleetRegistry.worker_name == worker_name,
                WorkerFleetRegistry.instance_id == instance_id,
            )
        )
        return result.scalar_one_or_none()

    async def list_queue_consumers(self) -> list[WorkerFleetRegistry]:
        result = await self._db.execute(
            select(WorkerFleetRegistry).where(
                WorkerFleetRegistry.worker_type == "cf_queue_consumer"
            )
        )
        return list(result.scalars().all())

    async def list_cf_workers(self) -> list[WorkerFleetRegistry]:
        result = await self._db.execute(
            select(WorkerFleetRegistry).where(
                WorkerFleetRegistry.worker_type == "cf_worker"
            )
        )
        return list(result.scalars().all())

    async def list_pending_deploy(self) -> list[WorkerFleetRegistry]:
        """Workers where target_version differs from current_version."""
        result = await self._db.execute(
            select(WorkerFleetRegistry).where(
                WorkerFleetRegistry.auto_deploy_enabled.is_(True),
                WorkerFleetRegistry.target_version.isnot(None),
                WorkerFleetRegistry.target_version != WorkerFleetRegistry.current_version,
                WorkerFleetRegistry.status != "deploying",
            )
        )
        return list(result.scalars().all())

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

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


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

    async def list_for_worker(
        self, worker_name: str, limit: int = 50
    ) -> list[WorkerFleetEvent]:
        result = await self._db.execute(
            select(WorkerFleetEvent)
            .where(WorkerFleetEvent.worker_name == worker_name)
            .order_by(WorkerFleetEvent.occurred_at.desc())
            .limit(limit)
        )
        return list(result.scalars().all())

    async def create(
        self,
        worker_name: str,
        instance_id: str,
        event_type: str,
        triggered_by: str = "auto_scaler",
        from_value: Optional[str] = None,
        to_value: Optional[str] = None,
        metadata: Optional[dict] = None,
    ) -> WorkerFleetEvent:
        row = WorkerFleetEvent(
            id=uuid4(),
            worker_name=worker_name,
            instance_id=instance_id,
            event_type=event_type,
            triggered_by=triggered_by,
            from_value=from_value,
            to_value=to_value,
            metadata_json=metadata,
        )
        self._db.add(row)
        await self._db.flush()
        return row


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

    async def get(self) -> Optional[WorkerScalingConfig]:
        result = await self._db.execute(select(WorkerScalingConfig).limit(1))
        return result.scalar_one_or_none()

    async def get_or_create(self) -> WorkerScalingConfig:
        row = await self.get()
        if not row:
            row = WorkerScalingConfig(id=uuid4())
            self._db.add(row)
            await self._db.flush()
        return row

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