"""SQLAlchemy implementation of SummaryRepository."""

from __future__ import annotations

from collections.abc import Sequence
from typing import TYPE_CHECKING
from uuid import UUID

from sqlalchemy import delete, select

from noteflow.domain.entities import ActionItem, KeyPoint, Summary
from noteflow.infrastructure.converters import OrmConverter
from noteflow.infrastructure.persistence.models import (
    ActionItemModel,
    KeyPointModel,
    SummaryModel,
)
from noteflow.infrastructure.persistence.repositories._base import BaseRepository

if TYPE_CHECKING:
    from noteflow.domain.value_objects import MeetingId


class SqlAlchemySummaryRepository(BaseRepository):
    """SQLAlchemy implementation of SummaryRepository."""

    async def _add_key_points(self, summary_id: int, key_points: Sequence[KeyPoint]) -> None:
        """Add key points to a summary.

        Args:
            summary_id: Database ID of the summary.
            key_points: Key points to add. Their db_id fields are updated in place.
        """
        models: list[tuple[KeyPointModel, KeyPoint]] = []
        for position, kp in enumerate(key_points):
            kp_model = KeyPointModel(
                summary_id=summary_id,
                position=position,
                text=kp.text,
                start_time=kp.start_time,
                end_time=kp.end_time,
                segment_ids=kp.segment_ids,
            )
            self._session.add(kp_model)
            models.append((kp_model, kp))

        await self._session.flush()
        for kp_model, kp in models:
            kp.db_id = kp_model.id
            kp.position = kp_model.position

    async def _add_action_items(self, summary_id: int, action_items: Sequence[ActionItem]) -> None:
        """Add action items to a summary.

        Args:
            summary_id: Database ID of the summary.
            action_items: Action items to add. Their db_id fields are updated in place.
        """
        models: list[tuple[ActionItemModel, ActionItem]] = []
        for position, ai in enumerate(action_items):
            ai_model = ActionItemModel(
                summary_id=summary_id,
                position=position,
                text=ai.text,
                assignee=ai.assignee,
                due_date=ai.due_date,
                priority=ai.priority,
                segment_ids=ai.segment_ids,
                start_time=ai.start_time,
                end_time=ai.end_time,
            )
            self._session.add(ai_model)
            models.append((ai_model, ai))

        await self._session.flush()
        for ai_model, ai in models:
            ai.db_id = ai_model.id
            ai.position = ai_model.position

    async def save(self, summary: Summary) -> Summary:
        """Save or update a meeting summary.

        Args:
            summary: Summary to save.

        Returns:
            Saved summary with db_id populated.
        """
        # Check if summary exists for this meeting
        stmt = select(SummaryModel).where(SummaryModel.meeting_id == UUID(str(summary.meeting_id)))
        result = await self._session.execute(stmt)
        if existing := result.scalar_one_or_none():
            # Update existing summary
            existing.executive_summary = summary.executive_summary
            if summary.generated_at is not None:
                existing.generated_at = summary.generated_at
            existing.provider_name = summary.provider_name
            existing.model_name = summary.model_name
            existing.tokens_used = summary.tokens_used
            existing.latency_ms = summary.latency_ms
            existing.verification = summary.verification

            # Delete old key points and action items
            await self._session.execute(
                delete(KeyPointModel).where(KeyPointModel.summary_id == existing.id)
            )
            await self._session.execute(
                delete(ActionItemModel).where(ActionItemModel.summary_id == existing.id)
            )

            # Add new key points and action items
            await self._add_key_points(existing.id, summary.key_points)
            await self._add_action_items(existing.id, summary.action_items)
            summary.db_id = existing.id
        else:
            # Create new summary
            model = SummaryModel(
                meeting_id=UUID(str(summary.meeting_id)),
                executive_summary=summary.executive_summary,
                generated_at=summary.generated_at,
                provider_name=summary.provider_name,
                model_name=summary.model_name,
                tokens_used=summary.tokens_used,
                latency_ms=summary.latency_ms,
                verification=summary.verification,
            )
            self._session.add(model)
            await self._session.flush()

            # Add key points and action items
            await self._add_key_points(model.id, summary.key_points)
            await self._add_action_items(model.id, summary.action_items)
            summary.db_id = model.id

        return summary

    async def get_by_meeting(self, meeting_id: MeetingId) -> Summary | None:
        """Get summary for a meeting.

        Args:
            meeting_id: Meeting identifier.

        Returns:
            Summary if exists, None otherwise.
        """
        stmt = select(SummaryModel).where(SummaryModel.meeting_id == UUID(str(meeting_id)))
        model = await self._execute_scalar(stmt)

        return None if model is None else OrmConverter.summary_to_domain(model, meeting_id)

    async def delete_by_meeting(self, meeting_id: MeetingId) -> bool:
        """Delete summary for a meeting.

        Args:
            meeting_id: Meeting identifier.

        Returns:
            True if deleted, False if not found.
        """
        stmt = select(SummaryModel).where(SummaryModel.meeting_id == UUID(str(meeting_id)))
        model = await self._execute_scalar(stmt)

        if model is None:
            return False

        await self._delete_and_flush(model)
        return True
