"""Mission-module link repository.

Handles the many-to-many junction table between missions and modules.
"""

from __future__ import annotations

import sqlite3

from pydantic import TypeAdapter

from unfamiliar.db.connection import DatabaseError
from unfamiliar.models import ModuleMissionLink

# Type adapter for parsing database rows into models
_module_link_adapter = TypeAdapter(ModuleMissionLink)


class MissionLinkRepository:
    """Repository for module-mission links.

    Handles the many-to-many relationship between modules and missions.
    """

    def __init__(self, conn: sqlite3.Connection) -> None:
        """Initialize repository with a database connection.

        Args:
            conn: A sqlite3.Connection with Row factory enabled.
        """
        self._conn = conn

    def link_modules(self, mission_id: int, links: list[ModuleMissionLink]) -> None:
        """Link modules to a mission.

        Args:
            mission_id: The mission's primary key.
            links: List of ModuleMissionLink objects.

        Raises:
            DatabaseError: On insert failure or invalid IDs.
        """
        if not links:
            return

        rows = [
            (link.module_id, mission_id, 1 if link.is_primary else 0) for link in links
        ]

        try:
            self._conn.executemany(
                """
                INSERT OR REPLACE INTO module_mission (
                    module_id, mission_id, is_primary
                ) VALUES (?, ?, ?)
                """,
                rows,
            )
            self._conn.commit()
        except sqlite3.Error as exc:
            raise DatabaseError("Failed to link modules") from exc

    def get_linked_modules(self, mission_id: int) -> list[ModuleMissionLink]:
        """Get module links for a mission.

        Args:
            mission_id: The mission's primary key.

        Returns:
            List of ModuleMissionLink objects.
        """
        rows = self._conn.execute(
            """
            SELECT module_id, mission_id, is_primary
            FROM module_mission
            WHERE mission_id = ?
            """,
            (mission_id,),
        ).fetchall()
        return [_row_to_module_link(row) for row in rows]

    def get_missions_for_module(self, module_id: int) -> list[int]:
        """Get mission IDs linked to a module.

        Args:
            module_id: The module's primary key.

        Returns:
            List of mission IDs.
        """
        rows = self._conn.execute(
            "SELECT mission_id FROM module_mission WHERE module_id = ?",
            (module_id,),
        ).fetchall()
        return [row["mission_id"] for row in rows]


def _row_to_module_link(row: sqlite3.Row) -> ModuleMissionLink:
    """Convert a database row to a ModuleMissionLink model."""
    return _module_link_adapter.validate_python(
        {
            "module_id": row["module_id"],
            "mission_id": row["mission_id"],
            "is_primary": bool(row["is_primary"]),
        }
    )
