"""Instructions domain - data access."""
from __future__ import annotations
from typing import Optional
from uuid import UUID

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

from src.domain.instructions.models import Prompt, PromptSession, ProjectInstruction, ProjectInstructionVersion


class InstructionRepository:
    def __init__(self, db: AsyncSession):
        self._db = db

    async def get_current_content(self, project_id: UUID) -> str:
        result = await self._db.execute(
            select(ProjectInstruction, ProjectInstructionVersion)
            .outerjoin(ProjectInstructionVersion, ProjectInstruction.current_version_id == ProjectInstructionVersion.id)
            .where(ProjectInstruction.project_id == project_id)
        )
        row = result.one_or_none()
        if not row or not row[1]:
            return ""
        return row[1].content

    async def create_version(self, project_id: UUID, content: str, created_by: Optional[UUID] = None) -> ProjectInstructionVersion:
        subq = select(ProjectInstructionVersion.version_number).where(
            ProjectInstructionVersion.project_id == project_id
        ).order_by(ProjectInstructionVersion.version_number.desc()).limit(1)
        result = await self._db.execute(subq)
        next_num = (result.scalar_one_or_none() or 0) + 1
        v = ProjectInstructionVersion(project_id=project_id, version_number=next_num, content=content, created_by=created_by)
        self._db.add(v)
        await self._db.flush()
        await self._db.refresh(v)
        return v

    async def set_current(self, project_id: UUID, version_id: UUID) -> None:
        result = await self._db.execute(select(ProjectInstruction).where(ProjectInstruction.project_id == project_id))
        pi = result.scalar_one_or_none()
        if not pi:
            pi = ProjectInstruction(project_id=project_id)
            self._db.add(pi)
            await self._db.flush()
        pi.current_version_id = version_id
        await self._db.flush()

    async def has_any_version(self, project_id: UUID) -> bool:
        result = await self._db.execute(
            select(ProjectInstructionVersion.id)
            .where(ProjectInstructionVersion.project_id == project_id)
            .limit(1)
        )
        return result.scalar_one_or_none() is not None


class PromptSessionRepository:
    def __init__(self, db: AsyncSession):
        self._db = db

    async def create(self, project_id: UUID, user_id: Optional[UUID], title: Optional[str] = None) -> PromptSession:
        s = PromptSession(project_id=project_id, user_id=user_id, title=title)
        self._db.add(s)
        await self._db.flush()
        await self._db.refresh(s)
        return s

    async def get_by_id(self, session_id: UUID) -> Optional[PromptSession]:
        result = await self._db.execute(select(PromptSession).where(PromptSession.id == session_id))
        return result.scalar_one_or_none()

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


class PromptRepository:
    def __init__(self, db: AsyncSession):
        self._db = db

    async def get_sender_labels(self, prompts: list[Prompt]) -> dict[UUID, str]:
        """Resolve authors only for prompts already loaded within the authorized session."""
        from src.domain.auth.facades import UserFacadeImpl
        from src.domain.auth.repository import UserRepository

        labels = await UserFacadeImpl(UserRepository(self._db)).get_user_labels(
            [p.user_id for p in prompts if p.user_id]
        )
        return {p.id: labels[p.user_id] for p in prompts if p.user_id in labels}

    async def create(
        self,
        session_id: UUID,
        content: str,
        user_id: Optional[UUID] = None,
        context: Optional[dict] = None,
    ) -> Prompt:
        p = Prompt(session_id=session_id, content=content, user_id=user_id, context=context)
        self._db.add(p)
        await self._db.flush()
        await self._db.refresh(p)
        return p

    async def get_by_id(self, prompt_id: UUID) -> Optional[Prompt]:
        result = await self._db.execute(select(Prompt).where(Prompt.id == prompt_id))
        return result.scalar_one_or_none()

    async def update_response(self, prompt_id: UUID, response: str) -> None:
        from sqlalchemy import update as sa_update
        await self._db.execute(
            sa_update(Prompt).where(Prompt.id == prompt_id).values(response=response)
        )

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