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

from app.domain import site as site_rules
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.runtime.log import logger
from app.schemas.message import Message
from app.schemas.types import NotificationChannel


site_interaction_manager = SlashInteractionManager()


class SiteInteractionRepository(Protocol):
    """站点消息交互所需的同步数据端口。"""

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

    def get(self, site_id: int) -> Optional[Any]:
        """按 ID 返回站点。"""

    def update(self, site_id: int, payload: dict) -> Optional[Any]:
        """更新站点。"""


class SiteInteractionHandler:
    """
    管理 /sites 交互会话、输入解析和站点列表渲染。
    """

    _button_page_size = 6
    _text_page_size = 10

    def __init__(
            self,
            messenger: MessageGateway,
            cookie_updater: Callable[..., Tuple[bool, str]],
            repository: SiteInteractionRepository,
    ):
        """
        注入消息投递接口和站点 Cookie 更新动作。
        """
        self._messenger = messenger
        self._cookie_updater = cookie_updater
        self._repository = repository

    def remote_list(
            self,
            arg_str: str = "",
            channel: NotificationChannel = None,
            userid: Union[str, int] = None,
            source: Optional[str] = None,
    ):
        """
        /sites 统一入口。
        """
        request = site_interaction_manager.create_or_replace(
            user_id=userid,
            command="/sites",
            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_site_interaction(
            request=request,
            channel=channel,
            source=source,
            userid=userid,
            username="",
        )

    @staticmethod
    def parse_callback(callback_data: str) -> Optional[Tuple[str, str]]:
        """
        解析 /sites 按钮回调。
        """
        if not callback_data.startswith("sites:"):
            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:
        """
        处理 /sites 按钮交互。
        """
        parsed = self.parse_callback(callback_data)
        if not parsed:
            return False

        request_id, action = parsed
        request = site_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="站点交互已失效，请重新发送 /sites",
                )
            )
            return True

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

        if action == "close":
            site_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 {"cookie", "enable", "disable"}:
            request.awaiting_input = action
        elif action == "refresh":
            request.awaiting_input = None

        self._render_site_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:
        """处理 /sites 文本交互并保持消息链公开 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:
        """
        处理 /sites 文本补充输入。
        """
        request = site_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"}:
            site_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_site_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if lowered in {"刷新", "refresh", "列表", "list"}:
            request.awaiting_input = None
            self._render_site_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_site_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_site_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        cookie_match = re.match(
            r"^(?:cookie|更新cookie|更新\s*cookie)\s+(.+)$",
            normalized,
            re.IGNORECASE,
        )
        enable_match = re.match(r"^(?:启用|enable)\s+(.+)$", normalized, re.IGNORECASE)
        disable_match = re.match(
            r"^(?:禁用|disable)\s+(.+)$", normalized, re.IGNORECASE
        )

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

        if request.awaiting_input == "enable":
            success, message = self._set_sites_enabled(normalized, enabled=True)
            request.awaiting_input = None
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_site_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if request.awaiting_input == "disable":
            success, message = self._set_sites_enabled(normalized, enabled=False)
            request.awaiting_input = None
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_site_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if cookie_match:
            success, message = self._update_site_cookie_from_input(cookie_match.group(1))
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_site_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if enable_match:
            success, message = self._set_sites_enabled(enable_match.group(1), enabled=True)
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_site_interaction(
                request=request,
                channel=channel,
                source=source,
                userid=userid,
                username=username,
            )
            return True

        if disable_match:
            success, message = self._set_sites_enabled(
                disable_match.group(1), enabled=False
            )
            self._messenger.post_message(
                Message(
                    channel=channel,
                    source=source,
                    userid=userid,
                    username=username,
                    title=message,
                )
            )
            self._render_site_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._site_usage_hint(request.awaiting_input),
            )
        )
        return True

    def _render_site_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:
        """
        渲染 /sites 当前页面。
        """
        site_list = self._repository.list()
        page_size = self._button_page_size if supports_interaction_buttons(channel) else self._text_page_size
        page_sites, page, total_pages = page_items(site_list, request.page, page_size)
        request.page = page

        if site_list:
            body = self._format_site_list(page_sites, channel=channel)
            footer = [
                f"第 {page + 1}/{total_pages} 页，共 {len(site_list)} 个站点",
                self._site_prompt(request.awaiting_input),
                self._site_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("sites", request, page, total_pages)
            buttons.extend(
                [
                    [
                        {
                            "text": "更新 Cookie",
                            "callback_data": f"sites:{request.request_id}:cookie",
                        },
                        {
                            "text": "禁用站点",
                            "callback_data": f"sites:{request.request_id}:disable",
                        },
                        {
                            "text": "启用站点",
                            "callback_data": f"sites:{request.request_id}:enable",
                        },
                    ],
                    [
                        {
                            "text": "刷新列表",
                            "callback_data": f"sites:{request.request_id}:refresh",
                        },
                        {
                            "text": "关闭",
                            "callback_data": f"sites:{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,
        )

    @staticmethod
    def _format_site_list(
            site_list: List[Any], channel: Optional[NotificationChannel]
    ) -> str:
        """
        根据渠道能力格式化站点列表。
        """
        if supports_markdown(channel):
            rows = [
                [
                    site.id,
                    site.name,
                    "启用" if site.is_active else "禁用",
                    "已配置" if site.cookie else "未配置",
                    "是" if site.render else "否",
                    site.domain or site_rules.extract_domain(site.url or ""),
                ]
                for site in site_list
            ]
            return format_markdown_table(
                headers=["ID", "站点", "状态", "Cookie", "渲染", "域名"],
                rows=rows,
            )

        lines = []
        for site in site_list:
            lines.append(
                f"{site.id}. {site.name} | 状态：{'启用' if site.is_active else '禁用'}"
                f" | Cookie：{'已配置' if site.cookie else '未配置'}"
                f" | 渲染：{'是' if site.render else '否'}"
                f" | 域名：{site.domain or site_rules.extract_domain(site.url or '')}"
            )
        return "\n".join(lines)

    @staticmethod
    def _site_prompt(awaiting_input: Optional[str]) -> str:
        """
        返回当前输入模式提示。
        """
        if awaiting_input == "cookie":
            return "当前操作：更新站点 Cookie，请输入：<id> <username> <password> [2fa_code/secret]"
        if awaiting_input == "enable":
            return "当前操作：启用站点，请输入站点 ID，多个 ID 用空格分隔。"
        if awaiting_input == "disable":
            return "当前操作：禁用站点，请输入站点 ID，多个 ID 用空格分隔。"
        return ""

    @staticmethod
    def _site_usage_hint(awaiting_input: Optional[str]) -> str:
        """
        返回 /sites 的文本操作提示。
        """
        if awaiting_input == "cookie":
            return "输入站点 ID、用户名、密码和可选 2FA；输入 `取消` 返回列表，输入 `退出` 结束交互。"
        if awaiting_input in {"enable", "disable"}:
            return "输入一个或多个站点 ID；输入 `取消` 返回列表，输入 `退出` 结束交互。"
        return (
            "可输入：`cookie <id> <username> <password> [2fa]`、`启用 <id...>`、`禁用 <id...>`、"
            "`n`、`p`、`刷新`、`退出`。"
        )

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

    def _set_sites_enabled(self, arg_str: str, enabled: bool) -> Tuple[bool, str]:
        """
        批量启用或禁用站点。
        """
        site_ids = self._parse_site_ids(arg_str)
        if not site_ids:
            return False, "请输入至少一个有效的站点 ID"

        changed = []
        missing = []
        for site_id in site_ids:
            site = self._repository.get(site_id)
            if not site:
                missing.append(str(site_id))
                continue
            self._repository.update(site_id, {"is_active": enabled})
            changed.append(site.name)

        action = "启用" if enabled else "禁用"
        if not changed and missing:
            return False, f"未找到站点：{', '.join(missing)}"

        message = f"已{action} {len(changed)} 个站点"
        if changed:
            message += f"：{', '.join(changed)}"
        if missing:
            message += f"；未找到：{', '.join(missing)}"
        return True, message

    def _update_site_cookie_from_input(self, arg_str: str) -> Tuple[bool, str]:
        """
        根据输入更新单个站点 Cookie。
        """
        args = str(arg_str or "").split()
        if len(args) not in {3, 4} or not args[0].isdigit():
            return (
                False,
                "格式错误，请输入：cookie <id> <username> <password> [2fa_code/secret]",
            )

        site_id = int(args[0])
        site_info = self._repository.get(site_id)
        if not site_info:
            return False, f"站点编号 {site_id} 不存在"

        status, msg = self._cookie_updater(
            site_info=site_info,
            username=args[1],
            password=args[2],
            two_step_code=args[3] if len(args) == 4 else None,
        )
        if not status:
            logger.error(msg)
            return False, f"【{site_info.name}】Cookie&UA 更新失败：{msg}"
        return True, f"【{site_info.name}】Cookie&UA 更新成功"
