"""[Channel] patches — relax access-control restrictions managed by the WebUI."""

from __future__ import annotations


def apply() -> None:
    """Patch 1: BaseChannel.is_allowed  — empty allow_from list → allow all (same as ["*"]).
    Patch 2: ChannelManager._validate_allow_from — no-op; WebUI manages this via UI.
    Patch 3: ChannelManager._dispatch_outbound — _subagent_hint shares send_tool_hints switch.
    Patch 4: DingTalkChannel.send() — rich card title for SubAgent results.
    Patch 5: FeishuChannel.send() — indigo header card for SubAgent results.
    """
    import asyncio
    import json

    from loguru import logger
    from nanobot.channels import base as _base
    from nanobot.channels import manager as _manager

    # ── Patch 1 & 2: access control ──────────────────────────────────────────

    def _is_allowed_patched(self, sender_id: str) -> bool:
        allow_list = getattr(self.config, "allow_from", [])
        if not allow_list or "*" in allow_list:
            return True
        return str(sender_id) in allow_list

    _base.BaseChannel.is_allowed = _is_allowed_patched  # type: ignore[method-assign]
    _manager.ChannelManager._validate_allow_from = lambda self: None  # type: ignore[method-assign]

    # ── Patch 3: _dispatch_outbound — subagent hint shares send_tool_hints ───

    async def _dispatch_outbound_patched(self) -> None:  # type: ignore[override]
        logger.info("Outbound dispatcher started")
        while True:
            try:
                msg = await asyncio.wait_for(
                    self.bus.consume_outbound(),
                    timeout=1.0,
                )
                if msg.metadata.get("_progress"):
                    if msg.metadata.get("_subagent_hint") or msg.metadata.get("_tool_hint"):
                        # SubAgent and main-agent tool-call hints — both controlled by send_tool_hints
                        if not self.config.channels.send_tool_hints:
                            continue
                    else:
                        # General progress messages
                        if not self.config.channels.send_progress:
                            continue

                channel = self.channels.get(msg.channel)
                if channel:
                    try:
                        await channel.send(msg)
                    except Exception as e:
                        logger.error("Error sending to {}: {}", msg.channel, e)
                else:
                    logger.warning("Unknown channel: {}", msg.channel)

            except asyncio.TimeoutError:
                continue
            except asyncio.CancelledError:
                break

    _manager.ChannelManager._dispatch_outbound = _dispatch_outbound_patched  # type: ignore[method-assign]

    # ── Patch 4: DingTalk — rich card title for SubAgent results ─────────────

    try:
        from nanobot.channels.dingtalk import DingTalkChannel
        _original_dt_send = DingTalkChannel.send

        async def _dingtalk_send_patched(self, msg) -> None:  # type: ignore[override]
            if msg.metadata.get("_subagent_result") and msg.content and msg.content.strip():
                token = await self._get_access_token()
                if token:
                    status_icon = "✅" if "✅" in msg.content else "❌"
                    title = f"{status_icon} SubAgent Task Complete"
                    await self._send_batch_message(
                        token,
                        msg.chat_id,
                        "sampleMarkdown",
                        {"text": msg.content.strip(), "title": title},
                    )
                    for media_ref in msg.media or []:
                        await self._send_media_ref(token, msg.chat_id, media_ref)
                return
            await _original_dt_send(self, msg)

        DingTalkChannel.send = _dingtalk_send_patched  # type: ignore[method-assign]
        logger.debug("DingTalkChannel.send patched for SubAgent cards")
    except ImportError:
        pass

    # ── Patch 5: Feishu — indigo header card for SubAgent results ────────────

    try:
        from nanobot.channels.feishu import FeishuChannel
        _original_fs_send = FeishuChannel.send

        async def _feishu_send_patched(self, msg) -> None:  # type: ignore[override]
            if msg.metadata.get("_subagent_result") and msg.content and msg.content.strip():
                if not self._client:
                    logger.warning("Feishu client not initialized")
                    return
                try:
                    loop = asyncio.get_running_loop()
                    receive_id_type = "chat_id" if msg.chat_id.startswith("oc_") else "open_id"
                    status_ok = "✅" in msg.content
                    header_text = "SubAgent Task Complete" if status_ok else "SubAgent Task Failed"
                    elements = self._build_card_elements(msg.content)
                    for chunk in self._split_elements_by_table_limit(elements):
                        card = {
                            "config": {"wide_screen_mode": True},
                            "header": {
                                "title": {"tag": "plain_text", "content": header_text},
                                "template": "indigo" if status_ok else "red",
                            },
                            "elements": chunk,
                        }
                        await loop.run_in_executor(
                            None, self._send_message_sync,
                            receive_id_type, msg.chat_id, "interactive",
                            json.dumps(card, ensure_ascii=False),
                        )
                    return
                except Exception as e:
                    logger.error("Feishu SubAgent card send failed: {}", e)
            await _original_fs_send(self, msg)

        FeishuChannel.send = _feishu_send_patched  # type: ignore[method-assign]
        logger.debug("FeishuChannel.send patched for SubAgent cards")
    except ImportError:
        pass
