"""Notification worker — sends Telegram completion messages to users."""
from __future__ import annotations

import uuid
from datetime import datetime, timezone

import redis.asyncio as aioredis
import structlog
import structlog.contextvars

from app.config import get_settings
from app.db.models.job import JobStatus
from app.db.repositories.job import JobRepository
from app.db.repositories.media import MediaRepository
from app.db.session import AsyncSessionLocal
from app.bot.messages import t
from app.services.queue import QueueService
from app.workers.base import BaseWorker

log = structlog.get_logger(__name__)
settings = get_settings()


def _format_date_ar(dt: datetime | None) -> str:
    if not dt:
        return "—"
    months_ar = [
        "يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو",
        "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر",
    ]
    months_en = [
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    ]
    return f"{dt.day} {months_ar[dt.month - 1]} {dt.year}"


def _format_date_en(dt: datetime | None) -> str:
    if not dt:
        return "—"
    return dt.strftime("%b %d, %Y")


class NotifyWorker(BaseWorker):
    stream = "notif:send"
    group = "notif:send-workers"

    def __init__(
        self,
        redis_client: aioredis.Redis,
        queue: QueueService,
        bot_token: str,
        worker_id: int = 0,
    ) -> None:
        super().__init__(redis_client, queue)
        self._bot_token = bot_token
        self.consumer_name = f"notif-worker-{worker_id}"

    async def _process(self, fields: dict[str, str]) -> None:
        job_id = uuid.UUID(fields["job_id"])
        structlog.contextvars.bind_contextvars(job_id=str(job_id))

        async with AsyncSessionLocal() as session:
            job_repo = JobRepository(session)
            media_repo = MediaRepository(session)

            job = await job_repo.get(job_id)
            if not job:
                return

            lock_key = f"job:{job_id}:lock"
            acquired = await self._r.set(lock_key, self.consumer_name, nx=True, ex=120)
            if not acquired:
                return

            try:
                claimed = await job_repo.transition(job_id, JobStatus.PENDING, JobStatus.RUNNING)
                if not claimed:
                    return
                await session.commit()

                entity_id = job.entity_id
                entity_type = job.entity_type or "media"
                chat_id = int(job.payload.get("chat_id", 0))
                lang = job.payload.get("lang", "ar")

                if not chat_id:
                    log.warning("notify.no_chat_id", job_id=str(job_id))
                    await job_repo.transition(job_id, JobStatus.RUNNING, JobStatus.DONE)
                    await session.commit()
                    return

                # Fetch entity + analysis
                analysis = await media_repo.get_analysis(entity_id, entity_type)

                if entity_type == "media":
                    item = await media_repo.get_media_item(entity_id)
                    title = (item.page_title if item else "") or "—"
                    domain = _extract_domain(item.source_url if item else "")
                    saved_at = item.created_at if item else None
                else:
                    link = await media_repo.get_link(entity_id)
                    title = (link.page_title if link else "") or "—"
                    domain = _extract_domain(link.url if link else "")
                    saved_at = link.created_at if link else None

                summary = (analysis.summary if analysis else "") or ""
                tags_raw = analysis.keywords if analysis and analysis.keywords else []
                tags_str = " ".join(f"#{tag}" for tag in tags_raw[:5]) if tags_raw else "—"

                date_str = (
                    _format_date_ar(saved_at) if lang == "ar" else _format_date_en(saved_at)
                )

                if summary:
                    text = t(
                        "save_complete", lang,
                        title=title, domain=domain, date=date_str,
                        summary=summary, tags=tags_str
                    )
                else:
                    text = t(
                        "save_complete_no_summary", lang,
                        title=title, domain=domain, date=date_str, tags=tags_str
                    )

                await self._send_telegram_message(chat_id, text)

                await job_repo.transition(job_id, JobStatus.RUNNING, JobStatus.DONE)
                await session.commit()

                log.info("notify.sent", chat_id=chat_id, entity_id=str(entity_id))

            except Exception as exc:
                log.error("notify.failed", job_id=str(job_id), error=str(exc))
                await job_repo.transition(
                    job_id, JobStatus.RUNNING, JobStatus.FAILED, error_message=str(exc)
                )
                await session.commit()
            finally:
                await self._r.delete(lock_key)

        structlog.contextvars.unbind_contextvars("job_id")

    async def _send_telegram_message(self, chat_id: int, text: str) -> None:
        import httpx
        url = f"https://api.telegram.org/bot{self._bot_token}/sendMessage"
        payload = {
            "chat_id": chat_id,
            "text": text,
            "parse_mode": "HTML",
        }
        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.post(url, json=payload)
            if resp.status_code != 200:
                raise RuntimeError(f"Telegram sendMessage failed: {resp.text[:200]}")


def _extract_domain(url: str) -> str:
    from urllib.parse import urlparse
    host = urlparse(url).hostname or url
    return host.removeprefix("www.")
