"""Handler for plain text messages (URLs and search queries)."""
from __future__ import annotations

import uuid

import structlog
from telegram import Update
from telegram.ext import ContextTypes

from app.bot.keyboards import save_mode_keyboard
from app.bot.messages import t
from app.bot.session import SessionManager
from app.db.models import Job, JobStatus, JobType, Link, LinkStatus, MediaItem, MediaStatus, User
from app.db.repositories.job import JobRepository
from app.db.repositories.media import MediaRepository
from app.db.repositories.user import UserRepository
from app.exceptions import DuplicateMediaError, ValidationError
from app.services.queue import QueueService
from app.utils.url import detect_platform, url_to_hash, validate_url

log = structlog.get_logger(__name__)


async def handle_message(
    update: Update,
    context: ContextTypes.DEFAULT_TYPE,
    session: SessionManager,
    user_repo: UserRepository,
    media_repo: MediaRepository,
    job_repo: JobRepository,
    queue: QueueService,
) -> None:
    if not update.effective_user or not update.message or not update.message.text:
        return

    tg_user = update.effective_user
    text = update.message.text.strip()
    lang = await session.get_field(tg_user.id, "lang", "ar")
    state = await session.get_field(tg_user.id, "state", "idle")

    # Route based on conversation state
    if state == "awaiting_search_query":
        await _handle_search_query(update, text, lang, session, tg_user.id, media_repo)
        return

    # Otherwise treat as a URL submission
    await _handle_url_submission(
        update, text, lang, session, tg_user, user_repo, media_repo, job_repo, queue
    )


async def _handle_url_submission(
    update: Update,
    text: str,
    lang: str,
    session: SessionManager,
    tg_user: object,
    user_repo: UserRepository,
    media_repo: MediaRepository,
    job_repo: JobRepository,
    queue: QueueService,
) -> None:
    assert update.message is not None
    uid = tg_user.id  # type: ignore[attr-defined]

    try:
        normalized_url = validate_url(text)
    except ValidationError as exc:
        log.info("bot.url.invalid", telegram_id=uid, url=text, reason=str(exc))
        await update.message.reply_text(t("invalid_url", lang))
        return

    url_hash = url_to_hash(normalized_url)
    platform = detect_platform(normalized_url)

    # Check for duplicate
    existing_job = await job_repo.find_active_by_hash(url_hash)
    if existing_job:
        log.info("bot.url.duplicate", telegram_id=uid, hash=url_hash)
        await update.message.reply_text(t("duplicate_url", lang, date="—"))
        return

    # Ensure user exists in DB
    db_user = await user_repo.get_or_create(tg_user_id=uid, username=getattr(tg_user, "username", None))

    # Store pending URL in session for save-mode callback
    await session.update(
        uid,
        state="awaiting_save_mode",
        pending_url=normalized_url,
        pending_hash=url_hash,
        pending_platform=platform,
        db_user_id=str(db_user.id),
    )

    await update.message.reply_text(
        t("url_received", lang, url=normalized_url),
        reply_markup=save_mode_keyboard(lang),
    )
    log.info("bot.url.received", telegram_id=uid, platform=platform, hash=url_hash)


async def _handle_search_query(
    update: Update,
    query: str,
    lang: str,
    session: SessionManager,
    telegram_id: int,
    media_repo: MediaRepository,
) -> None:
    assert update.message is not None
    await session.update(telegram_id, state="idle")
    # Search is handled by a dedicated service; stub here returns prompt
    # Full implementation wired in dispatcher after search service is injected
    await update.message.reply_text(t("search_no_results", lang, query=query))
    log.info("bot.search.query", telegram_id=telegram_id, query=query[:100])
