import os
import logging
from typing import Optional, Callable, Any, Awaitable, Union

logger = logging.getLogger("llm_smart_router.notification")


# 通知勾子型別定義
# 簽名: (provider, old_model, new_model) -> Union[Any, Awaitable[Any]]
NotifyCallback = Callable[[str, str, str], Union[Any, Awaitable[Any]]]


def create_slack_notifier(
    token: Optional[str] = None,
    channel: Optional[str] = None,
    username: str = "LLM Smart Router"
) -> NotifyCallback:
    """
    建立 Slack 非同步通知函數 (使用官方 slack-sdk 的 AsyncWebClient)
    
    Args:
        token: Slack Bot Token,若未指定則從環境變數 SLACK_BOT_TOKEN 讀取
        channel: 目標頻道 ID 或名稱 (例如 "#alerts"),若未指定則從 SLACK_CHANNEL 讀取
        username: 發送者名稱 (預設 "LLM Smart Router")
    
    Returns:
        非同步通知函數
    """
    slack_token = token or os.environ.get("SLACK_BOT_TOKEN")
    slack_channel = channel or os.environ.get("SLACK_CHANNEL")
    
    if not slack_token:
        raise ValueError("Slack Token 未設定。請設定 SLACK_BOT_TOKEN 環境變數。")
    if not slack_channel:
        raise ValueError("Slack Channel 未設定。請設定 SLACK_CHANNEL 環境變數。")

    async def notify(provider: str, old_model: str, new_model: str) -> None:
        try:
            from slack_sdk.web.async_client import AsyncWebClient
            from slack_sdk.errors import SlackApiError
        except ImportError:
            logger.warning("請安裝 slack-sdk 以使用此功能: pip install slack-sdk")
            return

        client = AsyncWebClient(token=slack_token)
        
        text = (
            f"🔄 *模型自動替換通知*\n"
            f"• Provider: `{provider}`\n"
            f"• 原模型: `{old_model}`\n"
            f"• 新模型: `{new_model}`\n"
            f"• 建議更新程式碼中的模型設定"
        )
        
        try:
            await client.chat_postMessage(
                channel=slack_channel,
                text=text,
                username=username
            )
            logger.debug("Slack 通知發送成功")
        except SlackApiError as e:
            logger.warning(f"Slack 通知發送失敗: {e.response['error']}")
        except Exception as e:
            logger.warning(f"Slack 通知發送出錯: {e}")

    return notify


def create_line_notifier(
    channel_token: Optional[str] = None,
    user_id: Optional[str] = None
) -> NotifyCallback:
    """
    建立 Line 非同步通知函數 (使用官方 line-bot-sdk v3 的 AsyncMessagingApi)
    
    Args:
        channel_token: Line Channel Access Token,若未指定則從環境變數 LINE_CHANNEL_TOKEN 讀取
        user_id: 接收者 User ID,若未指定則從環境變數 LINE_USER_ID 讀取
    
    Returns:
        非同步通知函數
    """
    token = channel_token or os.environ.get("LINE_CHANNEL_TOKEN")
    uid = user_id or os.environ.get("LINE_USER_ID")
    
    if not token:
        raise ValueError("Line Channel Token 未設定。請設定 LINE_CHANNEL_TOKEN 環境變數。")
    if not uid:
        raise ValueError("Line User ID 未設定。請設定 LINE_USER_ID 環境變數。")

    async def notify(provider: str, old_model: str, new_model: str) -> None:
        try:
            from linebot.v3.messaging import (
                Configuration,
                AsyncApiClient,
                AsyncMessagingApi,
                PushMessageRequest,
                TextMessage
            )
        except ImportError:
            logger.warning("請安裝 line-bot-sdk 以使用此功能: pip install line-bot-sdk")
            return

        conf = Configuration(access_token=token)
        
        message_text = (
            f"🔄 模型自動替換通知\n\n"
            f"Provider: {provider}\n"
            f"原模型: {old_model}\n"
            f"新模型: {new_model}\n\n"
            f"建議更新程式碼中的模型設定"
        )
        
        try:
            async with AsyncApiClient(conf) as api_client:
                line_bot_api = AsyncMessagingApi(api_client)
                push_message_request = PushMessageRequest(
                    to=uid,
                    messages=[TextMessage(text=message_text)]
                )
                await line_bot_api.push_message(push_message_request)
                logger.debug("Line 通知發送成功")
        except Exception as e:
            logger.warning(f"Line 通知發送失敗: {e}")

    return notify


def create_console_notifier(prefix: str = "🔔") -> NotifyCallback:
    """建立控制台通知函數 (用於測試)"""
    def notify(provider: str, old_model: str, new_model: str) -> None:
        print(f"{prefix} [模型替換] {provider}: {old_model} → {new_model}")
    
    return notify


