import re
from typing import Any, Callable, List, Optional, Protocol, Tuple, Union

from app.application.messaging.interaction import (
    MessageGateway,
    SlashInteractionManager,
    build_navigation_buttons,
    format_markdown_table,
    page_items,
    supports_interaction_buttons,
    supports_markdown,
    update_or_post_message,
)
from app.schemas.message import Message
from app.schemas.types import NotificationChannel, MediaType


subscribe_interaction_manager = SlashInteractionManager()


class SubscribeInteractionActions(Protocol):
    """
    声明订阅交互需要调用的业务动作。
    """

    def refresh(self) -> Any:
        """执行订阅刷新。"""
        ...

    def check(self) -> Any:
        """执行订阅元数据检查。"""
        ...

    def search(self, **kwargs: Any) -> Any:
        """按消息入口参数执行订阅搜索。"""
        ...


class SubscribeInteractionRepository(Protocol):
    """订阅消息交互所需的同步数据端口。"""

    def list(self) -> List[Any]:
        """返回订阅列表。"""

    def get(self, subscribe_id: int) -> Optional[Any]:
        """按 ID 返回订阅。"""

    def check(self) -> Any:
        """执行订阅元数据检查。"""
        ...

    def search(self, **kwargs: Any) -> Any:
        """执行订阅搜索。"""
        ...


class SubscribeInteractionHandler:
    """
    管理 /subscribes 交互会话、按钮、文本输入和列表视图。
    """

    _button_page_size = 6
    _text_page_size = 10

    def __init__(
            self,
            messenger: MessageGateway,
            actions: SubscribeInteractionActions,
            repository: SubscribeInteractionRepository,
            delete_subscription: Callable[[int], bool],
    ) -> None:
        """
        注入消息投递接口和订阅业务动作。
        """
        self._messenger = messenger
        self._actions = actions
        self._repository = repository
        self._delete_subscription = delete_subscription

    def remote_list(
            self,
            arg_str: str = "",
            channel: NotificationChannel = None,
            userid: Union[str, int] = None,
            source: Optional[str] = None,
    ):
        """
        /subscribes 统一入口。
        """
        request = subscribe_interaction_manager.create_or_replace(
            user_id=userid,
            command="/subscribes",
            channel=channel,
            source=source,
            username=None,
        )
        normalized_arg = (arg_str or "").strip()
        if normalized_arg and self.handle_text_interaction(
                channel=channel,
                source=source,
                userid=userid,
                username="",
                text=normalized_arg,
        ):
            return
        self._render_subscribe_interaction(
            request=request,
            channel=channel,
            source=source,
            userid=userid,
            username="",
        )

    @staticmethod
    def parse_callback(callback_data: str) -> Optional[Tuple[str, str]]:
        """
        解析 /subscribes 按钮回调。
        """
        if not callback_data.startswith("subscribes:"):
            return None
        parts = callback_data.split(":")
        if len(parts) < 3:
            return None
        return parts[1], parts[2]

    def handle_callback_interaction(
            self,
            callback_data: str,
            channel: NotificationChannel,
            source: str,
            userid: Union[str, int],
            username: str,
            original_message_id: Optional[Union[str, int]] = None,
            original_chat_id: Optional[str] = None,
    ) -> bool:
        """
        处理 /subscribes 按钮交互。
        """
        parsed = self.parse_callback(callback_data)
        if not parsed:
            return False

        request_id, action = parsed
        request = subscribe_interaction_manager.get_by_id(request_id, userid)
        if not request:
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title="订阅交互已失效，请重新发送 /subscribes",
                )
            )
            return True

        request.channel = channel
        request.source = source
        request.username = username

        if action == "close":
            subscribe_interaction_manager.remove(request.request_id)
            update_or_post_message(
                chain=self._messenger,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
                title="订阅管理",
                text="订阅交互已结束",
                original_message_id=original_message_id,
                original_chat_id=original_chat_id,
            )
            return True

        if action == "page-prev":
            request.page = max(0, request.page - 1)
            request.awaiting_input = None
        elif action == "page-next":
            request.page += 1
            request.awaiting_input = None
        elif action in {"search", "delete"}:
            request.awaiting_input = action
        elif action == "refresh":
            request.awaiting_input = None
            self._run_refresh_action(channel, source, userid, username)
        elif action == "refresh-list":
            request.awaiting_input = None
        elif action == "metadata":
            request.awaiting_input = None
            self._run_metadata_refresh_action(channel, source, userid, username)

        self._render_subscribe_interaction(
            request=request,
            channel=channel,
            source=source,
            userid=userid,
            username=username,
            original_message_id=original_message_id,
            original_chat_id=original_chat_id,
        )
        return True

    def handle_text_interaction(
            self,
            channel: NotificationChannel,
            source: str,
            userid: Union[str, int],
            username: str,
            text: str,
    ) -> bool:
        """处理 /subscribes 文本交互并保持消息链公开 ABI。"""
        return self._handle_text_interaction(channel, source, userid, username, text)

    def _handle_text_interaction(
            self,
            channel: NotificationChannel,
            source: str,
            userid: Union[str, int],
            username: str,
            text: str,
    ) -> bool:
        """
        处理 /subscribes 文本补充输入。
        """
        request = subscribe_interaction_manager.get_by_user(userid)
        if not request:
            return False

        request.channel = channel
        request.source = source
        request.username = username

        normalized = (text or "").strip()
        lowered = normalized.lower()

        if lowered in {"退出", "关闭", "q", "quit", "exit"}:
            subscribe_interaction_manager.remove(request.request_id)
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title="订阅交互已结束",
                    save_history=False,
                )
            )
            return True

        if lowered in {"取消", "cancel", "返回", "back"}:
            request.awaiting_input = None
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if lowered in {"刷新列表", "列表", "list"}:
            request.awaiting_input = None
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if lowered in {"刷新", "refresh"}:
            request.awaiting_input = None
            self._run_refresh_action(channel, source, userid, username)
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if lowered in {"元数据", "刷新元数据", "metadata"}:
            request.awaiting_input = None
            self._run_metadata_refresh_action(channel, source, userid, username)
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if lowered in {"p", "prev", "上一页"}:
            request.awaiting_input = None
            request.page = max(0, request.page - 1)
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if lowered in {"n", "next", "下一页"}:
            request.awaiting_input = None
            request.page += 1
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        search_match = re.match(r"^(?:搜索|search)\s+(.+)$", normalized, re.IGNORECASE)
        delete_match = re.match(r"^(?:删除|delete)\s+(.+)$", normalized, re.IGNORECASE)

        if request.awaiting_input == "search":
            success, message = self._run_search_action(
                normalized, channel, source, userid, username
            )
            request.awaiting_input = None
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if request.awaiting_input == "delete":
            success, message = self._delete_subscribes(normalized)
            request.awaiting_input = None
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if search_match:
            success, message = self._run_search_action(
                search_match.group(1), channel, source, userid, username
            )
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if delete_match:
            success, message = self._delete_subscribes(delete_match.group(1))
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_subscribe_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        self._messenger.post_message(
            Message(
                channel=channel,
                source=source,
                userid=userid,
                username=username,
                title=self._subscribe_usage_hint(request.awaiting_input),
            )
        )
        return True

    def _render_subscribe_interaction(
            self,
            request,
            channel: NotificationChannel,
            source: Optional[str],
            userid: Union[str, int],
            username: Optional[str],
            original_message_id: Optional[Union[str, int]] = None,
            original_chat_id: Optional[str] = None,
    ) -> None:
        """
        渲染 /subscribes 当前页面。
        """
        subscribes = self._repository.list()
        page_size = (
            self._button_page_size
            if supports_interaction_buttons(channel)
            else self._text_page_size
        )
        page_subscribes, page, total_pages = page_items(
            subscribes, request.page, page_size
        )
        request.page = page

        if subscribes:
            body = self._format_subscribe_list(page_subscribes, channel=channel)
            footer = [
                f"第 {page + 1}/{total_pages} 页，共 {len(subscribes)} 个订阅",
                self._subscribe_prompt(request.awaiting_input),
                self._subscribe_usage_hint(request.awaiting_input),
            ]
            text = "\n\n".join([body, *[line for line in footer if line]])
        else:
            text = "当前没有任何订阅。\n\n输入 `退出` 结束交互。"

        buttons = None
        if supports_interaction_buttons(channel):
            buttons = build_navigation_buttons(
                "subscribes", request, page, total_pages
            )
            buttons.extend(
                [
                    [
                        {
                            "text": "搜索订阅",
                            "callback_data": f"subscribes:{request.request_id}:search",
                        },
                        {
                            "text": "删除订阅",
                            "callback_data": f"subscribes:{request.request_id}:delete",
                        },
                        {
                            "text": "刷新订阅",
                            "callback_data": f"subscribes:{request.request_id}:refresh",
                        },
                    ],
                    [
                        {
                            "text": "刷新元数据",
                            "callback_data": f"subscribes:{request.request_id}:metadata",
                        },
                        {
                            "text": "刷新列表",
                            "callback_data": f"subscribes:{request.request_id}:refresh-list",
                        },
                        {
                            "text": "关闭",
                            "callback_data": f"subscribes:{request.request_id}:close",
                        },
                    ],
                ]
            )

        update_or_post_message(
            chain=self._messenger,
            channel=channel,
            source=source,
            userid=userid,
            username=username,
            title="订阅管理",
            text=text,
            buttons=buttons,
            original_message_id=original_message_id,
            original_chat_id=original_chat_id,
        )

    def _format_subscribe_list(
            self, subscribes: List[Any], channel: Optional[NotificationChannel]
    ) -> str:
        """
        根据渠道能力格式化订阅列表。
        """
        if supports_markdown(channel):
            rows = [
                [
                    subscribe.id,
                    subscribe.name,
                    subscribe.type,
                    subscribe.year or "-",
                    self._format_subscribe_progress(subscribe),
                    self._format_subscribe_state(subscribe.state),
                ]
                for subscribe in subscribes
            ]
            return format_markdown_table(
                headers=["ID", "名称", "类型", "年份", "季/进度", "状态"],
                rows=rows,
            )

        lines = []
        for subscribe in subscribes:
            lines.append(
                f"{subscribe.id}. {subscribe.name}（{subscribe.year or '-'}）"
                f" | {subscribe.type}"
                f" | {self._format_subscribe_progress(subscribe)}"
                f" | 状态：{self._format_subscribe_state(subscribe.state)}"
            )
        return "\n".join(lines)

    @staticmethod
    def _format_subscribe_state(state: Optional[str]) -> str:
        """
        订阅状态显示文本。
        """
        mapping = {
            "N": "新建",
            "R": "订阅中",
            "P": "待定",
            "S": "暂停",
        }
        return mapping.get(state or "", state or "-")

    @staticmethod
    def _format_subscribe_progress(subscribe: Any) -> str:
        """
        构造订阅的季和进度说明。
        """
        if subscribe.type == MediaType.MOVIE.value:
            return "电影"
        season = subscribe.season if subscribe.season is not None else 1
        if subscribe.total_episode:
            lack_episode = (
                subscribe.lack_episode
                if subscribe.lack_episode is not None
                else subscribe.total_episode
            )
            downloaded = max(subscribe.total_episode - lack_episode, 0)
            return f"第{season}季 [{downloaded}/{subscribe.total_episode}]"
        return f"第{season}季"

    @staticmethod
    def _subscribe_prompt(awaiting_input: Optional[str]) -> str:
        """
        返回当前输入模式提示。
        """
        if awaiting_input == "search":
            return "当前操作：搜索订阅，请输入订阅 ID，多个 ID 用空格分隔，或输入 all 搜索全部。"
        if awaiting_input == "delete":
            return "当前操作：删除订阅，请输入订阅 ID，多个 ID 用空格分隔。"
        return ""

    @staticmethod
    def _subscribe_usage_hint(awaiting_input: Optional[str]) -> str:
        """
        返回 /subscribes 的文本操作提示。
        """
        if awaiting_input == "search":
            return "输入订阅 ID 或 all；输入 `取消` 返回列表，输入 `退出` 结束交互。"
        if awaiting_input == "delete":
            return "输入一个或多个订阅 ID；输入 `取消` 返回列表，输入 `退出` 结束交互。"
        return (
            "可输入：`搜索 <id...|all>`、`删除 <id...>`、`刷新`、`刷新元数据`、`n`、`p`、`退出`。"
        )

    def _run_refresh_action(
            self,
            channel: NotificationChannel,
            source: str,
            userid: Union[str, int],
            username: str,
    ) -> None:
        """
        执行订阅刷新。
        """
        self._messenger.post_message(
            Message(
                channel=channel,
                source=source,
                userid=userid,
                username=username,
                title="开始刷新订阅...",
            )
        )
        self._actions.refresh()
        self._messenger.post_message(
            Message(
                channel=channel,
                source=source,
                userid=userid,
                username=username,
                title="订阅刷新执行完成",
            )
        )

    def _run_metadata_refresh_action(
            self,
            channel: NotificationChannel,
            source: str,
            userid: Union[str, int],
            username: str,
    ) -> None:
        """
        执行订阅元数据刷新。
        """
        self._messenger.post_message(
            Message(
                channel=channel,
                source=source,
                userid=userid,
                username=username,
                title="开始刷新订阅元数据...",
            )
        )
        self._actions.check()
        self._messenger.post_message(
            Message(
                channel=channel,
                source=source,
                userid=userid,
                username=username,
                title="订阅元数据刷新完成",
            )
        )

    @staticmethod
    def _parse_subscribe_ids(arg_str: str) -> List[int]:
        """
        从输入中提取订阅 ID。
        """
        return [int(item) for item in re.findall(r"\d+", arg_str or "")]

    def _run_search_action(
            self,
            arg_str: str,
            channel: NotificationChannel,
            source: str,
            userid: Union[str, int],
            username: str,
    ) -> Tuple[bool, str]:
        """
        手动执行订阅搜索。
        """
        normalized = (arg_str or "").strip()
        if not normalized or normalized.lower() in {"all", "全部", "所有"}:
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title="开始搜索所有订阅...",
                )
            )
            self._actions.search(state="N,R,P", manual=True)
            return True, "所有订阅搜索完成"

        subscribe_ids = self._parse_subscribe_ids(normalized)
        if not subscribe_ids:
            return False, "请输入订阅 ID，多个 ID 用空格分隔，或输入 all"

        missing = []
        searched = []
        for subscribe_id in subscribe_ids:
            subscribe = self._repository.get(subscribe_id)
            if not subscribe:
                missing.append(str(subscribe_id))
                continue
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=f"开始搜索订阅【{subscribe.name}】...",
                )
            )
            self._actions.search(sid=subscribe_id, manual=True)
            searched.append(subscribe.name)

        if not searched and missing:
            return False, f"未找到订阅：{', '.join(missing)}"

        message = f"已完成 {len(searched)} 个订阅搜索"
        if searched:
            message += f"：{', '.join(searched)}"
        if missing:
            message += f"；未找到：{', '.join(missing)}"
        return True, message

    def _delete_subscribes(self, arg_str: str) -> Tuple[bool, str]:
        """
        批量删除订阅。
        """
        subscribe_ids = self._parse_subscribe_ids(arg_str)
        if not subscribe_ids:
            return False, "请输入至少一个有效的订阅 ID"

        deleted = []
        missing = []
        for subscribe_id in subscribe_ids:
            subscribe = self._repository.get(subscribe_id)
            if not subscribe:
                missing.append(str(subscribe_id))
                continue
            if not self._delete_subscription(subscribe_id):
                missing.append(str(subscribe_id))
                continue
            deleted.append(subscribe.name)

        if not deleted and missing:
            return False, f"未找到订阅：{', '.join(missing)}"

        message = f"已删除 {len(deleted)} 个订阅"
        if deleted:
            message += f"：{', '.join(deleted)}"
        if missing:
            message += f"；未找到：{', '.join(missing)}"
        return True, message
