#!/usr/bin/env python3
"""
Article Studio — génère un article blog, une image à la une et des posts réseaux.

Entrée : URL source (--url) et/ou sujet (--sujet).
Sortie : dossier dans exports/article-studio/ (HTML, SEO, social, image).

Configuration : .secrets/.env (voir .secrets/.env.example)

Exemples :
  python3 scripts/wp_article_studio.py --sujet "Facturation électronique PrestaShop 2026"
  python3 scripts/wp_article_studio.py --url "https://exemple.com/article" --sujet "Même sujet, angle Arnaud"
  python3 scripts/wp_article_studio.py --sujet "..." --wp-draft
  python3 scripts/wp_article_studio.py --web
"""

from __future__ import annotations

import argparse
import json
import sys
import webbrowser
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import parse_qs, urlparse

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT / "scripts"))

from article_studio.config import default_model, load_config  # noqa: E402
from article_studio.pipeline import run_pipeline  # noqa: E402
from article_studio import wp_client  # noqa: E402

WEB_UI_HTML = """<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Article Studio</title>
  <style>
    :root { font-family: system-ui, sans-serif; color: #111; background: #f4f4f5; }
    body { max-width: 720px; margin: 2rem auto; padding: 0 1rem; }
    h1 { font-size: 1.5rem; margin-bottom: .25rem; }
    p.lead { color: #52525b; margin-top: 0; }
    label { display: block; font-weight: 600; margin: 1rem 0 .35rem; }
    input, textarea, select { width: 100%; box-sizing: border-box; padding: .55rem .65rem; border: 1px solid #d4d4d8; border-radius: 8px; font: inherit; }
    textarea { min-height: 100px; resize: vertical; }
    .row { display: flex; gap: 1rem; flex-wrap: wrap; }
    .row label { flex: 1; min-width: 200px; }
    .checks { display: flex; gap: 1.25rem; margin: 1rem 0; }
    .checks label { font-weight: 500; display: flex; align-items: center; gap: .4rem; }
    button { background: #18181b; color: #fff; border: 0; padding: .75rem 1.2rem; border-radius: 8px; font-weight: 600; cursor: pointer; }
    button:disabled { opacity: .6; cursor: wait; }
    #log { margin-top: 1.25rem; background: #fff; border: 1px solid #e4e4e7; border-radius: 8px; padding: 1rem; white-space: pre-wrap; font-family: ui-monospace, monospace; font-size: .85rem; min-height: 120px; }
    .ok { color: #166534; }
    .err { color: #b91c1c; }
    a { color: #2563eb; }
  </style>
</head>
<body>
  <h1>Article Studio</h1>
  <p class="lead">Génère article HTML, SEO, image et posts LinkedIn / X / Facebook — tout en local.</p>
  <form id="form">
    <label for="sujet">Sujet / angle (obligatoire)</label>
    <textarea id="sujet" name="sujet" required placeholder="Ex. Facturation électronique PrestaShop : conformité avant septembre 2026"></textarea>
    <label for="url">URL source (optionnel)</label>
    <input id="url" name="url" type="url" placeholder="https://…" />
    <label for="keywords">Mots-clés secondaires (optionnel)</label>
    <input id="keywords" name="keywords" type="text" />
    <div class="row">
      <label>Statut WP si brouillon créé
        <select id="wp_status" name="wp_status"><option value="draft">Brouillon</option><option value="publish">Publié</option></select>
      </label>
    </div>
    <div class="checks">
      <label><input type="checkbox" id="wp_draft" name="wp_draft" /> Créer le brouillon WordPress</label>
      <label><input type="checkbox" id="skip_image" name="skip_image" /> Sans image</label>
    </div>
    <button type="submit" id="btn">Générer</button>
  </form>
  <div id="log"></div>
  <script>
    const form = document.getElementById('form');
    const log = document.getElementById('log');
    const btn = document.getElementById('btn');
    form.addEventListener('submit', async (e) => {
      e.preventDefault();
      btn.disabled = true;
      log.textContent = 'Lancement…\\n';
      const fd = new FormData(form);
      try {
        const res = await fetch('/api/generate', { method: 'POST', body: fd });
        const data = await res.json();
        if (!res.ok) throw new Error(data.error || 'Erreur');
        log.innerHTML = data.logs.map(l => l).join('\\n') + '\\n\\n'
          + '<span class="ok">Terminé.</span> Dossier : ' + data.output_dir
          + (data.article_link ? '\\nArticle : ' + data.article_link : '');
      } catch (err) {
        log.innerHTML = '<span class="err">' + (err.message || err) + '</span>';
      } finally {
        btn.disabled = false;
      }
    });
  </script>
</body>
</html>
"""


def build_parser() -> argparse.ArgumentParser:
    ap = argparse.ArgumentParser(description="Article Studio — article + image + réseaux sociaux.")
    ap.add_argument("--sujet", "-s", help="Sujet ou angle de l’article")
    ap.add_argument("--url", "-u", help="URL d’un article source (inspiration)")
    ap.add_argument("--keywords", "-k", help="Mots-clés secondaires")
    ap.add_argument("--liens-internes", help="URLs internes à citer")
    ap.add_argument("--env", type=Path, help="Chemin .env (défaut : .secrets/.env)")
    ap.add_argument("--output", "-o", type=Path, help="Dossier de sortie")
    ap.add_argument("--no-image", action="store_true", help="Ne pas générer l’image")
    ap.add_argument(
        "--wp-draft",
        action="store_true",
        help="Créer un brouillon WordPress (avec image à la une si générée)",
    )
    ap.add_argument(
        "--wp-publish",
        action="store_true",
        help="Publier directement sur WordPress (attention)",
    )
    ap.add_argument("--test-wp", action="store_true", help="Tester la connexion WordPress et quitter")
    ap.add_argument("--web", action="store_true", help="Lancer l’interface web locale")
    ap.add_argument("--port", type=int, default=8765, help="Port interface web (défaut 8765)")
    return ap


def cmd_test_wp(cfg) -> int:
    if not cfg.wp_user or not cfg.wp_application_password:
        print("WP_USER / WP_APPLICATION_PASSWORD manquants.", file=sys.stderr)
        return 1
    me = wp_client.test_connection(cfg.wp_base_url, cfg.wp_user, cfg.wp_application_password)
    print(f"OK — {me.get('name')} (id {me.get('id')}) sur {cfg.wp_base_url}")
    return 0


def cmd_cli(args, cfg) -> int:
    if not args.sujet:
        print("Indique --sujet (obligatoire).", file=sys.stderr)
        return 1

    wp_status = "publish" if args.wp_publish else "draft"
    publish = args.wp_draft or args.wp_publish

    def printer(msg: str) -> None:
        print(msg)

    try:
        result = run_pipeline(
            cfg,
            sujet=args.sujet,
            source_url=args.url,
            keywords=args.keywords,
            internal_links=args.liens_internes,
            wp_status=wp_status,
            skip_image=args.no_image,
            publish_wp=publish,
            output_dir=args.output,
            on_log=printer,
        )
    except Exception as e:
        print(f"Erreur : {e}", file=sys.stderr)
        return 1

    print("\n--- Résumé ---")
    print(f"Dossier : {result.output_dir}")
    print(f"Article : {result.article_link}")
    if result.image_path:
        print(f"Image   : {result.image_path}")
    if result.parsed.social:
        print("Social  :", ", ".join(result.parsed.social.keys()))
    return 0


def cmd_web(cfg, port: int) -> int:
    state = {"cfg": cfg}

    class Handler(BaseHTTPRequestHandler):
        def log_message(self, fmt, *args):  # noqa: ARG002
            return

        def _send(self, code: int, body: bytes, content_type: str) -> None:
            self.send_response(code)
            self.send_header("Content-Type", content_type)
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)

        def do_GET(self) -> None:  # noqa: N802
            path = urlparse(self.path).path
            if path in ("/", "/index.html"):
                self._send(200, WEB_UI_HTML.encode("utf-8"), "text/html; charset=utf-8")
                return
            self._send(404, b"Not found", "text/plain")

        def do_POST(self) -> None:  # noqa: N802
            if urlparse(self.path).path != "/api/generate":
                self._send(404, b"Not found", "text/plain")
                return
            length = int(self.headers.get("Content-Length", 0))
            raw = self.rfile.read(length).decode("utf-8", errors="replace")
            # multipart minimal
            fields: dict[str, str] = {}
            if "boundary=" in self.headers.get("Content-Type", ""):
                boundary = self.headers["Content-Type"].split("boundary=")[-1]
                for part in raw.split("--" + boundary):
                    if "name=" not in part:
                        continue
                    name_match = __import__("re").search(r'name="([^"]+)"', part)
                    if not name_match:
                        continue
                    name = name_match.group(1)
                    chunks = part.split("\r\n\r\n", 1)
                    if len(chunks) < 2:
                        continue
                    val = chunks[1].rsplit("\r\n", 1)[0]
                    fields[name] = val
            else:
                fields = {k: v[0] for k, v in parse_qs(raw).items()}

            sujet = fields.get("sujet", "").strip()
            if not sujet:
                self._send(400, json.dumps({"error": "Sujet obligatoire"}).encode(), "application/json")
                return

            logs: list[str] = []

            try:
                result = run_pipeline(
                    state["cfg"],
                    sujet=sujet,
                    source_url=fields.get("url") or None,
                    keywords=fields.get("keywords") or None,
                    wp_status=fields.get("wp_status", "draft"),
                    skip_image=fields.get("skip_image") == "on",
                    publish_wp=fields.get("wp_draft") == "on",
                    on_log=logs.append,
                )
                payload = {
                    "output_dir": str(result.output_dir),
                    "article_link": result.article_link,
                    "logs": logs,
                }
                self._send(200, json.dumps(payload, ensure_ascii=False).encode(), "application/json")
            except Exception as e:
                self._send(500, json.dumps({"error": str(e)}).encode(), "application/json")

    server = ThreadingHTTPServer(("127.0.0.1", port), Handler)
    url = f"http://127.0.0.1:{port}/"
    print(f"Article Studio — {url}")
    print(f"LLM : {cfg.llm_provider} / {cfg.llm_model or default_model(cfg.llm_provider)}")
    webbrowser.open(url)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\nArrêt.")
    return 0


def main() -> int:
    ap = build_parser()
    args = ap.parse_args()

    try:
        cfg = load_config(env_path=args.env)
    except FileNotFoundError as e:
        print(e, file=sys.stderr)
        return 1

    if args.test_wp:
        return cmd_test_wp(cfg)
    if args.web:
        return cmd_web(cfg, args.port)
    if not args.sujet and not args.url:
        ap.print_help()
        return 1
    return cmd_cli(args, cfg)


if __name__ == "__main__":
    raise SystemExit(main())
