"""Shared handler helpers: job lookup, safe editing and Persian rendering."""

from __future__ import annotations

import logging
import re
from typing import Any

from aiogram.exceptions import TelegramAPIError, TelegramBadRequest
from aiogram.types import CallbackQuery, InlineKeyboardMarkup, Message

from app.context import AppContext
from app.database.models import Job, VideoStatus
from app.errors import AppError, JobStateError
from app.utils.formatting import (
    VIDEO_STATUS_LABELS,
    esc,
    format_job_summary,
    safe_url_display,
    status_label,
)

logger = logging.getLogger(__name__)
_URL_RE = re.compile(r"https?://[^\s<>\"']+", re.IGNORECASE)
_VIDEO_STATUS_ORDER = (
    VideoStatus.PENDING,
    VideoStatus.DOWNLOADING,
    VideoStatus.DOWNLOADED,
    VideoStatus.UPLOADING,
    VideoStatus.UPLOADED,
    VideoStatus.FAILED,
    VideoStatus.UPLOAD_UNKNOWN,
    VideoStatus.SKIPPED,
    VideoStatus.CANCELLED,
)


def first_argument(args: str | None) -> str | None:
    if not args:
        return None
    parts = args.strip().split()
    return parts[0] if parts else None


def extract_url(text: str) -> str:
    """Take a complete URL from a pasted message, never rewriting a hostname."""

    match = _URL_RE.search(text or "")
    return match.group(0).rstrip(".,;:!؟)»]") if match else (text or "").strip()


async def resolve_job(ctx: AppContext, token: str | None) -> Job:
    token = (token or "").strip().lstrip("#")
    if token:
        exact = await ctx.repo.get_job(token)
        if exact is not None:
            return exact
        jobs = await ctx.repo.list_jobs(limit=500)
        matches = [job for job in jobs if job.id.startswith(token.lower())]
        if len(matches) == 1:
            return matches[0]
        if len(matches) > 1:
            raise JobStateError("این شناسه کوتاه بین چند عملیات مشترک است؛ شناسه بیشتری بفرستید.")
        raise JobStateError("عملیاتی با این شناسه پیدا نشد.")
    latest = await ctx.repo.latest_active_job()
    if latest is None:
        raise JobStateError("هیچ عملیات فعالی وجود ندارد.")
    return latest


async def job_detail_text(ctx: AppContext, job: Job) -> str:
    text = format_job_summary(job, detail=True)
    counts = await ctx.repo.video_status_counts(job.id)
    if counts:
        lines = ["", "<b>وضعیت ویدئوها</b>"]
        for status in _VIDEO_STATUS_ORDER:
            amount = counts.get(status.value, 0)
            if amount:
                lines.append(f"• {esc(VIDEO_STATUS_LABELS[status.value])}: {amount}")
        text += "\n".join(lines)
    return text


async def safe_edit(
    callback: CallbackQuery,
    text: str,
    reply_markup: InlineKeyboardMarkup | None = None,
) -> None:
    message = callback.message
    if isinstance(message, Message):
        try:
            await message.edit_text(
                text,
                parse_mode="HTML",
                disable_web_page_preview=True,
                reply_markup=reply_markup,
            )
            return
        except TelegramBadRequest as exc:
            if "message is not modified" in str(exc).lower():
                return
            logger.debug("edit failed, sending a new message instead: %s", exc)
        except TelegramAPIError:
            logger.debug("edit failed, sending a new message instead", exc_info=True)
    try:
        await callback.bot.send_message(
            chat_id=callback.from_user.id,
            text=text,
            parse_mode="HTML",
            disable_web_page_preview=True,
            reply_markup=reply_markup,
        )
    except TelegramAPIError:
        logger.warning("could not deliver callback response")


def error_text(exc: BaseException) -> str:
    if isinstance(exc, AppError):
        return exc.user_message
    return "خطای غیرمنتظره رخ داد. جزئیات در گزارش ربات ثبت شد."


async def send_job_card(message: Message, ctx: AppContext, job: Job) -> None:
    from app.keyboards.menus import job_actions_keyboard

    await message.answer(
        await job_detail_text(ctx, job),
        parse_mode="HTML",
        disable_web_page_preview=True,
        reply_markup=job_actions_keyboard(job),
    )


def history_text_from_jobs(jobs: list[Job]) -> str:
    if not jobs:
        return "<b>📜 تاریخچه</b>\n\nهنوز عملیاتی ثبت نشده است."
    lines = ["<b>📜 آخرین عملیات‌ها</b>", ""]
    for job in jobs:
        lines.append(
            f"• <code>{esc(job.short_id)}</code> — {esc(status_label(job.status))} — "
            f"ارسال {job.uploaded_videos} از {job.total_videos}\n"
            f"  <code>{esc(safe_url_display(job.source_url, 100))}</code>"
        )
    return "\n".join(lines)


def history_text_from_videos(videos: list[Any]) -> str:
    if not videos:
        return "<b>📜 تاریخچه ارسال‌ها</b>\n\nهنوز ویدئویی با موفقیت ارسال نشده است."
    lines = ["<b>📜 آخرین ویدئوهای ارسال‌شده</b>", ""]
    for video in videos:
        when = (video.uploaded_at or "").replace("T", " ")[:16]
        lines.append(
            f"• {esc(video.title[:90])}\n"
            f"  <code>{esc(when or '—')}</code> — "
            f"پیام <code>{video.telegram_message_id or '—'}</code>\n"
            f"  <code>{esc(safe_url_display(video.source_url, 100))}</code>"
        )
    return "\n".join(lines)
