import logging
from pathlib import Path
from typing import Literal, assert_never, cast

import telebot
from django.conf import settings

from cyber_valley.common.telegram import require_telegram_bot_token
from cyber_valley.notifications.helpers import send_notification
from cyber_valley.shaman_verification.models import VerificationRequest
from cyber_valley.users.models import UserSocials

log = logging.getLogger(__name__)


def create_verification_caption(
    metadata_cid: str,
    verification_type: str,
    status: Literal["pending", "approved", "declined"] = "pending",
    requester_chat_id: int | None = None,
    requester_username: str | None = None,
) -> str:
    """Create caption for verification request message based on status."""
    ipfs_url = f"{settings.IPFS_PUBLIC_HOST}/ipfs/{metadata_cid}"

    header: str
    match status:
        case "pending":
            header = "๐Ÿ”” New Shaman Verification Request"
        case "approved":
            header = "โœ… Verification request has been approved"
        case "declined":
            header = "โŒ Verification request has been declined"
        case _ as unreachable:
            assert_never(unreachable)

    # Format IPFS link as HTML
    ipfs_link = f'<a href="{ipfs_url}">View on IPFS</a>'

    # Build caption parts
    caption_parts = [header, f"\nType: {verification_type}"]

    # Add requester info if available
    if requester_chat_id:
        requester_display = requester_username or "User"
        requester_link = (
            f'<a href="tg://user?id={requester_chat_id}">@{requester_display}</a>'
        )
        caption_parts.append(f"Requester: {requester_link}")

    caption_parts.append(f"IPFS Metadata: {ipfs_link}")

    return "\n".join(caption_parts)


def send_verification_request_to_provider(
    chat_id: int, verification_request_id: int, username: str | None = None
) -> None:
    """Send a single verification request to a local provider via Telegram."""
    token = require_telegram_bot_token()
    bot = telebot.TeleBot(token)

    try:
        verification_request = VerificationRequest.objects.get(
            id=verification_request_id
        )
    except VerificationRequest.DoesNotExist:
        log.exception(
            "Verification request %s not found, cannot send to provider",
            verification_request_id,
        )
        return
    assert verification_request.requester_id is not None

    telegram_social = verification_request.requester.socials.filter(
        network=UserSocials.Network.TELEGRAM
    ).first()
    assert telegram_social is not None
    requester_chat_id = int(telegram_social.value)
    requester_username = (
        telegram_social.metadata.get("username") if telegram_social.metadata else None
    )

    caption = create_verification_caption(
        metadata_cid=verification_request.metadata_cid,
        verification_type=verification_request.verification_type,
        status="pending",
        requester_chat_id=requester_chat_id,
        requester_username=requester_username,
    )

    markup = telebot.types.InlineKeyboardMarkup()
    markup.add(
        telebot.types.InlineKeyboardButton(
            "โœ… Approve", callback_data=f"approve:{verification_request.id}"
        ),
        telebot.types.InlineKeyboardButton(
            "โŒ Decline", callback_data=f"decline:{verification_request.id}"
        ),
    )

    # Get files from filesystem using UUID
    verification_path = (
        settings.IPFS_DATA_PATH / "verifications" / str(verification_request.uuid)
    )
    files: list[tuple[str, Path]] = []

    if (
        verification_request.verification_type
        == VerificationRequest.VerificationType.INDIVIDUAL
    ):
        # Find ktp file in the UUID directory
        for ktp_path in verification_path.glob("ktp_*"):
            files.append(("ktp", ktp_path))
            break
    elif (
        verification_request.verification_type
        == VerificationRequest.VerificationType.COMPANY
    ):
        # Find all required files in the UUID directory
        for field in ("ktp", "akta", "sk"):
            for field_path in verification_path.glob(f"{field}_*"):
                files.append((field, field_path))
                break

    if not files:
        log.warning(
            "No files found for verification request %s, sending message without media",
            verification_request_id,
        )
        bot.send_message(chat_id, caption, reply_markup=markup, parse_mode="HTML")
        return

    # Send media group with caption
    media_group = []
    for _, file_path in files:
        file_obj = cast(telebot.types.InputFile, file_path.open("rb"))
        media = telebot.types.InputMediaDocument(
            file_obj,
        )
        media_group.append(media)

    messages = bot.send_media_group(chat_id, media_group)  # type: ignore[arg-type]
    assert len(messages) == len(files)
    bot.reply_to(
        messages[-1],
        caption,
        parse_mode="HTML",
        reply_markup=markup,
    )

    username_display = f"@{username}" if username else chat_id
    log.info(
        "Sent verification request %s to provider %s",
        verification_request_id,
        username_display,
    )


def send_all_pending_verifications_to_provider(
    chat_id: int, username: str | None = None
) -> None:
    """Send all pending verification requests to a local provider."""
    pending_verifications = VerificationRequest.objects.filter(
        status=VerificationRequest.Status.PENDING
    )

    count = pending_verifications.count()
    if count == 0:
        log.info("No pending verifications to send to provider")
        return

    log.info("Sending %s pending verification requests to provider", count)

    for verification_request in pending_verifications:
        try:
            send_verification_request_to_provider(
                chat_id=chat_id,
                verification_request_id=verification_request.id,
                username=username,
            )
        except Exception:
            log.exception(
                "Failed to send verification request %s to provider",
                verification_request.id,
            )


def notify_shaman_of_decision(
    verification_request: VerificationRequest, is_update: bool = False
) -> None:
    """Notify shaman about verification decision via web and Telegram."""
    if verification_request.status == VerificationRequest.Status.PENDING:
        return

    status_display = (
        "Approved"
        if verification_request.status == VerificationRequest.Status.APPROVED
        else "Declined"
    )
    update_prefix = "Updated: " if is_update else ""

    title = f"{update_prefix}Verification Request {status_display}"
    body = (
        f"Your {verification_request.verification_type} verification request "
        f"has been {status_display.lower()}."
    )

    notification = send_notification(
        user=verification_request.requester,
        title=title,
        body=body,
    )

    if notification:
        log.info(
            "Sent notification to shaman %s about verification %s status: %s",
            verification_request.requester_id,
            verification_request.id,
            status_display,
        )

Graph