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

from datetime import datetime, timezone
from typing import Optional
from uuid import UUID, uuid4

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

from src.domain.project_storage.models import ProjectStorageBucket, ProjectStorageUsage


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

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

    async def count_active(self, project_id: UUID) -> int:
        from sqlalchemy import func

        result = await self._db.execute(
            select(func.count())
            .select_from(ProjectStorageBucket)
            .where(
                ProjectStorageBucket.project_id == project_id,
                ProjectStorageBucket.is_active.is_(True),
            )
        )
        return result.scalar_one()

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

    async def create(
        self,
        *,
        project_id: UUID,
        name: str,
        access_policy: str,
        rls_enabled: bool,
        cdn_enabled: bool,
        cdn_custom_domain: Optional[str],
        allowed_mime_types_json: Optional[list],
        max_file_size_bytes: Optional[int],
    ) -> ProjectStorageBucket:
        row = ProjectStorageBucket(
            id=uuid4(),
            project_id=project_id,
            name=name,
            access_policy=access_policy,
            rls_enabled=rls_enabled,
            cdn_enabled=cdn_enabled,
            cdn_custom_domain=cdn_custom_domain,
            allowed_mime_types_json=allowed_mime_types_json,
            max_file_size_bytes=max_file_size_bytes,
        )
        self._db.add(row)
        await self._db.flush()
        return row

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


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

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

    async def apply_delta(
        self,
        project_id: UUID,
        delta_bytes: int,
        delta_files: int,
    ) -> ProjectStorageUsage:
        """Atomically apply a storage delta. Upserts the row if it doesn't exist."""
        row = await self.get_for_project(project_id)
        now = datetime.now(timezone.utc)
        if row:
            row.total_bytes = max(0, row.total_bytes + delta_bytes)
            row.total_files = max(0, row.total_files + delta_files)
            row.last_updated_at = now
        else:
            row = ProjectStorageUsage(
                id=uuid4(),
                project_id=project_id,
                total_bytes=max(0, delta_bytes),
                total_files=max(0, delta_files),
                last_updated_at=now,
            )
            self._db.add(row)
        await self._db.flush()
        return row
