"""AI 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.ai.models import (
    ProjectAIConfig,
    ProjectAIEmbedConfig,
    WorkspaceVectorizeConfig,
)


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

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

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

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


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

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

    async def get_by_entity_field(
        self, project_id: UUID, entity_key: str, field_key: str
    ) -> Optional[ProjectAIEmbedConfig]:
        result = await self._db.execute(
            select(ProjectAIEmbedConfig).where(
                ProjectAIEmbedConfig.project_id == project_id,
                ProjectAIEmbedConfig.entity_key == entity_key,
                ProjectAIEmbedConfig.field_key == field_key,
            )
        )
        return result.scalar_one_or_none()

    async def create(
        self,
        project_id: UUID,
        entity_key: str,
        field_key: str,
        auto_embed: bool,
        model_override: Optional[str],
    ) -> ProjectAIEmbedConfig:
        row = ProjectAIEmbedConfig(
            id=uuid4(),
            project_id=project_id,
            entity_key=entity_key,
            field_key=field_key,
            auto_embed=auto_embed,
            model_override=model_override,
        )
        self._db.add(row)
        await self._db.flush()
        return row

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

    async def delete(self, row: ProjectAIEmbedConfig) -> None:
        await self._db.delete(row)
        await self._db.flush()


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

    async def get_by_workspace(
        self, workspace_id: UUID
    ) -> Optional[WorkspaceVectorizeConfig]:
        result = await self._db.execute(
            select(WorkspaceVectorizeConfig).where(
                WorkspaceVectorizeConfig.workspace_id == workspace_id
            )
        )
        return result.scalar_one_or_none()

    async def create(
        self,
        workspace_id: UUID,
        vectorize_index_id: str,
        index_name: str,
        dimensions: int,
        metric: str,
    ) -> WorkspaceVectorizeConfig:
        row = WorkspaceVectorizeConfig(
            id=uuid4(),
            workspace_id=workspace_id,
            vectorize_index_id=vectorize_index_id,
            index_name=index_name,
            dimensions=dimensions,
            metric=metric,
        )
        self._db.add(row)
        await self._db.flush()
        return row

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