"""DatabaseTodoProvider — persistent todos через SQLAlchemy (Postgres + SQLite).

Dialect-agnostic SQL. Multi-tenant: user_id + topic_id.
"""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any

from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

from cognitia.todo.types import TodoItem


class DatabaseTodoProvider:
    """TodoProvider через SQLAlchemy async (Postgres/SQLite).

    SQL изолирован внутри класса. LSP: заменяет InMemory и FS.
    """

    def __init__(self, session_factory: Any, user_id: str, topic_id: str, max_todos: int = 100) -> None:
        self._session_factory = session_factory
        self._user_id = user_id
        self._topic_id = topic_id
        self._max_todos = max_todos

    async def _get_session(self) -> AsyncSession:
        session: AsyncSession = self._session_factory()
        return session

    async def read_todos(self) -> list[TodoItem]:
        """Прочитать все todos пользователя/топика."""
        async with await self._get_session() as session:
            result = await session.execute(
                text("SELECT id, content, status, created_at, updated_at FROM todos WHERE user_id = :u AND topic_id = :t ORDER BY created_at"),
                {"u": self._user_id, "t": self._topic_id},
            )
            rows = result.fetchall()
            return [
                TodoItem(
                    id=row[0], content=row[1], status=row[2],
                    created_at=row[3] if isinstance(row[3], datetime) else datetime.now(tz=timezone.utc),
                    updated_at=row[4] if isinstance(row[4], datetime) else datetime.now(tz=timezone.utc),
                )
                for row in rows
            ]

    async def write_todos(self, todos: list[TodoItem]) -> None:
        """Записать todos (bulk replace): удаляет все + вставляет новые."""
        if len(todos) > self._max_todos:
            msg = f"Превышен лимит max_todos ({self._max_todos})"
            raise ValueError(msg)

        async with await self._get_session() as session:
            # Удаляем все текущие todos
            await session.execute(
                text("DELETE FROM todos WHERE user_id = :u AND topic_id = :t"),
                {"u": self._user_id, "t": self._topic_id},
            )
            # Вставляем новые
            for item in todos:
                await session.execute(
                    text("""
                        INSERT INTO todos (id, user_id, topic_id, content, status, created_at, updated_at)
                        VALUES (:id, :u, :t, :content, :status, :created, :updated)
                    """),
                    {
                        "id": item.id, "u": self._user_id, "t": self._topic_id,
                        "content": item.content, "status": item.status,
                        "created": item.created_at.isoformat() if isinstance(item.created_at, datetime) else str(item.created_at),
                        "updated": item.updated_at.isoformat() if isinstance(item.updated_at, datetime) else str(item.updated_at),
                    },
                )
            await session.commit()
