"""Merge live blog inventory, DB articles, and link targets for planning/content."""

from __future__ import annotations

import re
from typing import Any

from blogs.models import BlogArticle, BlogSettings


def _normalize(text: str) -> str:
    return re.sub(r"\s+", " ", (text or "").strip().lower())


def gather_db_articles() -> list[dict[str, Any]]:
    rows = []
    for art in BlogArticle.objects.order_by("-created_at"):
        url = (art.shopify_article_url or "").strip()
        rows.append(
            {
                "source": "db",
                "title": art.title or "",
                "target_keyword": art.target_keyword or "",
                "secondary_keywords": art.secondary_keywords or [],
                "status": art.status,
                "url": url,
                "slug": art.slug or "",
            }
        )
    return rows


def gather_existing_coverage(settings_obj: BlogSettings | None = None) -> dict[str, Any]:
    settings_obj = settings_obj or BlogSettings.load()
    external = settings_obj.external_blog_inventory or []
    db_articles = gather_db_articles()

    seen_urls: set[str] = set()
    seen_titles: set[str] = set()
    articles: list[dict[str, Any]] = []
    link_targets: list[dict[str, str]] = []

    for item in external:
        if not isinstance(item, dict):
            continue
        url = (item.get("url") or "").strip()
        title = (item.get("title") or "").strip()
        norm_url = _normalize(url)
        norm_title = _normalize(title)
        if norm_url and norm_url in seen_urls:
            continue
        if norm_title and norm_title in seen_titles:
            continue
        if norm_url:
            seen_urls.add(norm_url)
        if norm_title:
            seen_titles.add(norm_title)
        articles.append({**item, "source": "live"})
        if url and title:
            link_targets.append({"title": title, "url": url})

    for row in db_articles:
        url = row.get("url") or ""
        title = row.get("title") or ""
        norm_url = _normalize(url)
        norm_title = _normalize(title)
        if norm_url and norm_url in seen_urls:
            continue
        if norm_title and norm_title in seen_titles:
            continue
        if norm_url:
            seen_urls.add(norm_url)
            if title:
                link_targets.append({"title": title, "url": url})
        elif norm_title and norm_title not in seen_titles:
            seen_titles.add(norm_title)
        articles.append(row)

    keywords_covered: set[str] = set()
    for art in articles:
        kw = art.get("target_keyword") or ""
        if kw:
            keywords_covered.add(_normalize(kw))
        for t in art.get("main_topics") or []:
            if t:
                keywords_covered.add(_normalize(str(t)))
        for t in art.get("secondary_keywords") or []:
            if t:
                keywords_covered.add(_normalize(str(t)))

    live_lines = []
    for item in external[:40]:
        if not isinstance(item, dict):
            continue
        title = item.get("title") or "?"
        topics = ", ".join(item.get("main_topics") or [])[:120]
        live_lines.append(f"- {title} ({topics})")

    db_lines = []
    for row in db_articles[:40]:
        if row.get("title"):
            db_lines.append(
                f"- [{row.get('status')}] {row['title']} / {row.get('target_keyword', '')}"
            )

    summary_parts = []
    if live_lines:
        summary_parts.append("Live blog:\n" + "\n".join(live_lines))
    if db_lines:
        summary_parts.append("In-app articles:\n" + "\n".join(db_lines))
    if len(external) > 40:
        summary_parts.append(f"(+ {len(external) - 40} more live posts omitted)")
    if len(db_articles) > 40:
        summary_parts.append(f"(+ {len(db_articles) - 40} more DB articles omitted)")

    return {
        "articles": articles,
        "link_targets": link_targets,
        "keywords_covered": keywords_covered,
        "summary_for_prompt": "\n\n".join(summary_parts) or "No existing coverage recorded.",
        "live_count": len(external),
        "db_count": len(db_articles),
    }
