"""Planka-specific bot command handler."""

from __future__ import annotations

import logging
from collections.abc import Callable, Coroutine
from typing import Any

from ..database.models import (
    CommandConfig, CommandTracker, ServiceProvider, TelegramBot,
)
from ..services import make_planka_provider
from ..services.http_session import get_http_session
from .base import CommandResponse, ProviderCommandHandler
from .command_utils import get_last_event_str, get_tracked_collection_ids, get_trackers_for_provider
from .handler import _render_cmd_template

_LOGGER = logging.getLogger(__name__)

_PLANKA_COMMANDS = {"status", "boards", "cards", "lists"}


def _get_tracked_board_ids(
    provider: ServiceProvider,
    trackers: list,
) -> list[str]:
    """Get board IDs from tracked collection_ids for this provider."""
    if not provider.config.get("api_key"):
        return []
    return get_tracked_collection_ids(provider, trackers)


# ---------------------------------------------------------------------------
# Command dispatch table
# ---------------------------------------------------------------------------

_TEXT_COMMANDS: dict[str, Callable[..., Coroutine[Any, Any, dict[str, Any]]]] = {}


def _text_cmd(fn: Callable[..., Coroutine[Any, Any, dict[str, Any]]]) -> Callable[..., Coroutine[Any, Any, dict[str, Any]]]:
    """Register a function in the text command dispatch table."""
    name = fn.__name__.removeprefix("_cmd_")
    _TEXT_COMMANDS[name] = fn
    return fn


class PlankaCommandHandler(ProviderCommandHandler):
    """Handles Planka-specific bot commands."""

    provider_type = "planka"

    def get_provider_commands(self) -> set[str]:
        return _PLANKA_COMMANDS

    def get_rate_categories(self) -> dict[str, str]:
        return {
            "boards": "api", "cards": "api", "lists": "api",
        }

    async def handle(
        self,
        cmd: str,
        args: str,
        count: int,
        locale: str,
        response_mode: str,
        provider: ServiceProvider,
        cmd_templates: dict[str, dict[str, str]],
        bot: TelegramBot,
        tracker: CommandTracker,
        config: CommandConfig,
        *,
        listener: Any = None,
        allowed_album_ids: set[str] | None = None,  # noqa: ARG002 — unused (Planka has no album model)
        page: int = 1,
    ) -> CommandResponse | None:
        fn = _TEXT_COMMANDS.get(cmd)
        if fn is None:
            return None
        ctx = await fn(provider, count)
        return CommandResponse(text=_render_cmd_template(cmd_templates, cmd, locale, ctx))


@_text_cmd
async def _cmd_status(provider: ServiceProvider, count: int) -> dict[str, Any]:
    trackers = await get_trackers_for_provider(provider.id)
    tracked_boards = _get_tracked_board_ids(provider, trackers)

    tracker_ids = [t.id for t in trackers]
    last_str = await get_last_event_str(tracker_ids)

    return {
        "boards_count": len(tracked_boards),
        "last_event": last_str,
    }


@_text_cmd
async def _cmd_boards(provider: ServiceProvider, count: int) -> dict[str, Any]:
    trackers = await get_trackers_for_provider(provider.id)
    tracked_boards = _get_tracked_board_ids(provider, trackers)

    boards_data: list[dict[str, Any]] = []
    http = await get_http_session()
    planka = make_planka_provider(http, provider)
    all_boards = await planka.client.get_boards()
    board_names = {str(b.get("id", "")): b.get("name", "") for b in all_boards}
    for board_id in tracked_boards:
        boards_data.append({"name": board_names.get(board_id, board_id)})

    return {"boards": boards_data}


@_text_cmd
async def _cmd_cards(provider: ServiceProvider, count: int) -> dict[str, Any]:
    trackers = await get_trackers_for_provider(provider.id)
    tracked_boards = _get_tracked_board_ids(provider, trackers)

    all_cards: list[dict[str, Any]] = []
    http = await get_http_session()
    planka = make_planka_provider(http, provider)
    boards = await planka.client.get_boards()
    board_names = {str(b.get("id", "")): b.get("name", "") for b in boards}

    for board_id in tracked_boards:
        cards = await planka.client.get_board_cards(board_id, limit=count)
        lists = await planka.client.get_board_lists(board_id)
        lists_by_id = {str(lst.get("id", "")): lst.get("name", "") for lst in lists}
        board_name = board_names.get(board_id, board_id)

        for card in cards:
            list_id = str(card.get("listId", ""))
            all_cards.append({
                "name": card.get("name", ""),
                "list_name": lists_by_id.get(list_id, ""),
                "board_name": board_name,
            })

    return {"cards": all_cards[:count]}


@_text_cmd
async def _cmd_lists(provider: ServiceProvider, count: int) -> dict[str, Any]:
    trackers = await get_trackers_for_provider(provider.id)
    tracked_boards = _get_tracked_board_ids(provider, trackers)

    all_lists: list[dict[str, Any]] = []
    http = await get_http_session()
    planka = make_planka_provider(http, provider)
    boards = await planka.client.get_boards()
    board_names = {str(b.get("id", "")): b.get("name", "") for b in boards}

    for board_id in tracked_boards:
        lists = await planka.client.get_board_lists(board_id)
        board_name = board_names.get(board_id, board_id)

        for lst in lists:
            all_lists.append({
                "name": lst.get("name", ""),
                "board_name": board_name,
            })

    return {"lists": all_lists}
