from __future__ import annotations

import re
from collections.abc import Callable
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path

from .config import Config, api_key_for_provider, default_model
from .fetch_url import fetch_article_source
from .image_gen import generate_featured_image
from .llm import chat_completion
from .parser import ParsedArticle, article_url, parse_llm_output
from .prompts import build_user_prompt, load_master_prompt
from . import wp_client


@dataclass
class StudioResult:
    output_dir: Path
    parsed: ParsedArticle
    article_link: str
    wp_post: dict | None = None
    image_path: Path | None = None
    logs: list[str] = field(default_factory=list)


def _slugify(text: str) -> str:
    text = text.lower()
    text = re.sub(r"[^a-z0-9\s-]", "", text)
    text = re.sub(r"[\s_]+", "-", text.strip())
    return re.sub(r"-+", "-", text).strip("-") or "article"


def _write_outputs(out_dir: Path, parsed: ParsedArticle, raw: str, link: str) -> None:
    out_dir.mkdir(parents=True, exist_ok=True)
    (out_dir / "raw-llm.txt").write_text(raw, encoding="utf-8")

    seo_lines = [f"{k}: {v}" for k, v in parsed.seo.items()]
    (out_dir / "seo.yaml").write_text("\n".join(seo_lines) + "\n", encoding="utf-8")

    meta = parsed.meta
    (out_dir / "meta.json").write_text(
        __import__("json").dumps(meta, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )
    (out_dir / "article.html").write_text(parsed.html, encoding="utf-8")

    social_dir = out_dir / "social"
    social_dir.mkdir(exist_ok=True)
    for network, content in parsed.social.items():
        (social_dir / f"{network}.txt").write_text(content + "\n", encoding="utf-8")

    readme = f"""# Article Studio — export

- URL article : {link}
- Titre : {meta.get('title', '(sans titre)')}
- Slug : {parsed.seo.get('slug') or meta.get('slug', '')}

## Fichiers
- article.html — corps à coller dans WordPress
- seo.yaml — métadonnées Yoast
- meta.json — titre, excerpt, prompts image
- social/ — posts LinkedIn, X, Facebook prêts à coller
- image/featured.png — visuel à la une (si généré)
"""
    (out_dir / "README.md").write_text(readme, encoding="utf-8")


def run_pipeline(
    cfg: Config,
    *,
    sujet: str,
    source_url: str | None = None,
    keywords: str | None = None,
    internal_links: str | None = None,
    wp_status: str = "draft",
    skip_image: bool = False,
    publish_wp: bool = False,
    output_dir: Path | None = None,
    on_log: Callable[[str], None] | None = None,
) -> StudioResult:
    def log(msg: str) -> None:
        if on_log:
            on_log(msg)

    logs: list[str] = []

    def track(msg: str) -> None:
        logs.append(msg)
        log(msg)

    source = None
    if source_url:
        track(f"Récupération de la source : {source_url}")
        source = fetch_article_source(source_url)
        track(f"Source extraite — {len(source.get('text', ''))} caractères")

    slug_guess = _slugify(sujet[:80])
    link = article_url(cfg.wp_base_url, slug_guess)

    master = load_master_prompt(cfg.prompt_path)
    user_prompt = build_user_prompt(
        sujet=sujet,
        article_url=link,
        source=source,
        keywords=keywords,
        internal_links=internal_links,
        status=wp_status,
    )

    model = cfg.llm_model or default_model(cfg.llm_provider)
    api_key = api_key_for_provider(cfg)

    track(f"Génération LLM ({cfg.llm_provider} / {model})…")
    raw = chat_completion(cfg.llm_provider, api_key, model, master, user_prompt)
    parsed = parse_llm_output(raw)

    slug = parsed.seo.get("slug") or parsed.meta.get("slug") or slug_guess
    link = article_url(cfg.wp_base_url, slug)

    # Remplacer placeholder URL dans les posts sociaux
    for key, text in list(parsed.social.items()):
        parsed.social[key] = text.replace("{{ARTICLE_URL}}", link)

    stamp = datetime.now().strftime("%Y-%m-%d-%H%M")
    out_dir = output_dir or (cfg.exports_dir / f"{stamp}-{slug[:60]}")
    _write_outputs(out_dir, parsed, raw, link)
    track(f"Export local : {out_dir}")

    image_path = None
    image_prompt = parsed.meta.get("image_prompt", "")
    if not skip_image and image_prompt:
        if not cfg.openai_api_key:
            track("Image ignorée — OPENAI_API_KEY manquante (DALL-E).")
        else:
            track("Génération de l’image à la une…")
            image_path = generate_featured_image(
                cfg.openai_api_key,
                image_prompt,
                out_dir / "image" / "featured.png",
                model=cfg.llm_image_model,
            )
            (out_dir / "image" / "image-prompt.txt").write_text(image_prompt + "\n", encoding="utf-8")
            track(f"Image enregistrée : {image_path}")

    wp_post = None
    if publish_wp:
        if not cfg.wp_user or not cfg.wp_application_password:
            raise ValueError("WP_USER et WP_APPLICATION_PASSWORD requis pour --wp-draft.")
        track("Publication brouillon WordPress…")
        featured_id = None
        if image_path and image_path.is_file():
            media = wp_client.upload_media(
                cfg.wp_base_url,
                cfg.wp_user,
                cfg.wp_application_password,
                image_path,
                alt_text=parsed.meta.get("image_alt", ""),
                title=parsed.meta.get("title", ""),
            )
            featured_id = media.get("id")

        wp_post = wp_client.create_post(
            cfg.wp_base_url,
            cfg.wp_user,
            cfg.wp_application_password,
            title=parsed.meta.get("title") or parsed.seo.get("titre_seo", sujet),
            content=parsed.html,
            excerpt=parsed.meta.get("excerpt", ""),
            status=wp_status,
            slug=slug,
            featured_media_id=featured_id,
            yoast_title=parsed.seo.get("titre_seo"),
            yoast_description=parsed.seo.get("meta_description"),
            yoast_focus=parsed.seo.get("focus_keyword"),
        )
        link = wp_post.get("link", link)
        track(f"Brouillon WP créé — id {wp_post.get('id')} — {link}")

    return StudioResult(
        output_dir=out_dir,
        parsed=parsed,
        article_link=link,
        wp_post=wp_post,
        image_path=image_path,
        logs=logs,
    )
