import uuid
from typing import Optional

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

from app.models.models import FlaggedItem, ResolvedItem, ErrorItem, ProofVersion, Proof, Campaign


class AuditRepository:
    """Repository for audit-related database operations."""

    def __init__(self, session: AsyncSession):
        self.session = session

    # Flagged Items
    async def create_flagged_item(
        self,
        proof_version_id: uuid.UUID,
        agent_flagged: str,
        comments: Optional[str] = None,
        submitter_id: Optional[uuid.UUID] = None,
    ) -> FlaggedItem:
        """Create a new flagged item."""
        flagged = FlaggedItem(
            proof_version_id=proof_version_id,
            agent_flagged=agent_flagged,
            comments=comments,
            submitter_id=submitter_id,
        )
        self.session.add(flagged)
        await self.session.flush()
        return flagged

    async def get_flagged_items(
        self,
        agency_id: Optional[uuid.UUID] = None,
        limit: int = 100,
        offset: int = 0,
    ) -> list[FlaggedItem]:
        """Get all flagged items, optionally filtered by agency."""
        query = (
            select(FlaggedItem)
            .options(
                selectinload(FlaggedItem.proof_version)
                .selectinload(ProofVersion.proof)
                .selectinload(Proof.campaign),
                selectinload(FlaggedItem.submitter),
            )
            .join(ProofVersion)
            .join(Proof)
            .join(Campaign)
        )
        if agency_id:
            query = query.where(Campaign.agency_id == agency_id)
        query = query.order_by(FlaggedItem.created_at.desc()).limit(limit).offset(offset)

        result = await self.session.execute(query)
        return list(result.scalars().all())

    # Resolved Items
    async def create_resolved_item(
        self,
        proof_version_id: uuid.UUID,
        agent: str,
        issue: Optional[str] = None,
        resolution: Optional[str] = None,
        submitter_id: Optional[uuid.UUID] = None,
    ) -> ResolvedItem:
        """Create a new resolved item."""
        resolved = ResolvedItem(
            proof_version_id=proof_version_id,
            agent=agent,
            issue=issue,
            resolution=resolution,
            submitter_id=submitter_id,
        )
        self.session.add(resolved)
        await self.session.flush()
        return resolved

    async def get_resolved_items(
        self,
        agency_id: Optional[uuid.UUID] = None,
        limit: int = 100,
        offset: int = 0,
    ) -> list[ResolvedItem]:
        """Get all resolved items, optionally filtered by agency."""
        query = (
            select(ResolvedItem)
            .options(
                selectinload(ResolvedItem.proof_version)
                .selectinload(ProofVersion.proof)
                .selectinload(Proof.campaign),
                selectinload(ResolvedItem.submitter),
            )
            .join(ProofVersion)
            .join(Proof)
            .join(Campaign)
        )
        if agency_id:
            query = query.where(Campaign.agency_id == agency_id)
        query = query.order_by(ResolvedItem.created_at.desc()).limit(limit).offset(offset)

        result = await self.session.execute(query)
        return list(result.scalars().all())

    # Error Items
    async def create_error_item(
        self,
        proof_version_id: uuid.UUID,
        error_summary: Optional[str] = None,
    ) -> ErrorItem:
        """Create a new error item."""
        error = ErrorItem(
            proof_version_id=proof_version_id,
            error_summary=error_summary,
        )
        self.session.add(error)
        await self.session.flush()
        return error

    async def get_error_items(
        self,
        agency_id: Optional[uuid.UUID] = None,
        limit: int = 100,
        offset: int = 0,
    ) -> list[ErrorItem]:
        """Get all error items, optionally filtered by agency."""
        query = (
            select(ErrorItem)
            .options(
                selectinload(ErrorItem.proof_version)
                .selectinload(ProofVersion.proof)
                .selectinload(Proof.campaign),
            )
            .join(ProofVersion)
            .join(Proof)
            .join(Campaign)
        )
        if agency_id:
            query = query.where(Campaign.agency_id == agency_id)
        query = query.order_by(ErrorItem.created_at.desc()).limit(limit).offset(offset)

        result = await self.session.execute(query)
        return list(result.scalars().all())

    async def get_audit_log(
        self,
        agency_id: Optional[uuid.UUID] = None,
        limit: int = 100,
    ) -> dict:
        """Get combined audit log with flagged, resolved, and error items."""
        flagged = await self.get_flagged_items(agency_id=agency_id, limit=limit)
        resolved = await self.get_resolved_items(agency_id=agency_id, limit=limit)
        errors = await self.get_error_items(agency_id=agency_id, limit=limit)

        return {
            "flagged_items": flagged,
            "resolved_items": resolved,
            "error_items": errors,
        }
