"""
JamPulse Social Publish – fertige Videos automatisch auf TikTok + YouTube.

Modi:
  browser     – Upload-Seite öffnen, Video markieren, Caption in Zwischenablage (Standard)
  playwright  – Edge-Profil, Video + Text + optional Auto-Klick (Login einmalig nötig)
"""

from __future__ import annotations

import json
import os
import re
import shutil
import subprocess
import sys
import threading
import time
import webbrowser
from datetime import datetime
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
CONFIG_PATH = ROOT / "data" / "social-publish-config.json"
QUEUE_PATH = ROOT / "data" / "social-publish-queue.json"
STATUS_PATH = ROOT / "data" / "social-publish-status.json"

TIKTOK_ASSIST = ROOT / "scripts" / "tiktok_post_assist.py"
YOUTUBE_ASSIST = ROOT / "scripts" / "youtube_post_assist.py"

STUDIO_ROOT = Path.home() / "Documents" / "Jam-TikTok-Posten"
CLIPS_READY = STUDIO_ROOT / "clips-ready"
PUBLISH_INBOX = STUDIO_ROOT / "publish-inbox"


def _default_config() -> dict:
    return {
        "tiktok_enabled": True,
        "youtube_enabled": True,
        "instagram_enabled": True,
        "auto_after_video": True,
        "use_user_browser": True,
        "playwright_auto_publish": False,
        "youtube_studio_url": "https://studio.youtube.com/",
        "tiktok_account": "socialmedia.mentor",
        "default_tags": "#shorts #deutsch #jampulse",
    }


def load_config() -> dict:
    if CONFIG_PATH.is_file():
        try:
            data = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
            if isinstance(data, dict):
                return {**_default_config(), **data}
        except (json.JSONDecodeError, OSError):
            pass
    return _default_config()


def save_config(data: dict) -> None:
    CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
    CONFIG_PATH.write_text(
        json.dumps({**_default_config(), **data}, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )


def _caption_to_title(caption: str, *, max_len: int = 95) -> str:
    line = ""
    for raw in caption.splitlines():
        t = raw.strip()
        if t and not t.startswith("#"):
            line = t
            break
    if not line:
        line = caption.strip().split("#")[0].strip() or "JamPulse Video"
    return line[:max_len]


def _read_caption_file(path: Path | None) -> str:
    if path and path.is_file():
        return path.read_text(encoding="utf-8").strip()
    return ""


def _write_status(payload: dict) -> None:
    payload["updated_at"] = datetime.now().isoformat(timespec="seconds")
    STATUS_PATH.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def stage_video(video: Path, *, slot: str = "jampulse") -> Path:
    """Video in clips-ready legen für TikTok-Assistent."""
    CLIPS_READY.mkdir(parents=True, exist_ok=True)
    PUBLISH_INBOX.mkdir(parents=True, exist_ok=True)
    dest = CLIPS_READY / f"{slot}.mp4"
    shutil.copy2(video, dest)
    inbox = PUBLISH_INBOX / f"{datetime.now().strftime('%Y%m%d-%H%M%S')}-{slot}.mp4"
    shutil.copy2(video, inbox)
    return dest


def prepare_post_meta(
    *,
    video: Path,
    caption: str,
    title: str | None = None,
    slot: str = "jampulse",
    source: str = "jampulse",
) -> dict:
    cap = caption.strip()
    ttl = (title or _caption_to_title(cap)).strip()
    staged = stage_video(video, slot=slot) if video.is_file() else None
    meta = {
        "slot": slot,
        "source": source,
        "title": ttl,
        "caption": cap,
        "video": str(staged or video),
        "video_original": str(video),
        "prepared_at": time.time(),
        "when": datetime.now().isoformat(timespec="seconds"),
    }
    QUEUE_PATH.write_text(json.dumps(meta, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")

    try:
        from jam.tiktok_studio import write_last_post

        write_last_post(
            {
                "slot": slot,
                "hook": ttl,
                "caption": cap,
                "niche": "social_media_mentor",
                "niche_label": "JamPulse Auto",
                "account": load_config().get("tiktok_account", "socialmedia.mentor"),
            }
        )
    except ImportError:
        pass
    return meta


def _clipboard(text: str) -> None:
    try:
        subprocess.run(
            [
                "powershell",
                "-NoProfile",
                "-Command",
                f"Set-Clipboard -Value @'\n{text[:4000]}\n'@",
            ],
            check=False,
            timeout=10,
        )
    except OSError:
        pass


def publish_browser(
    meta: dict,
    *,
    tiktok: bool = True,
    youtube: bool = True,
    instagram: bool = False,
) -> dict:
    """Browser + Zwischenablage – du klickst nur noch Veröffentlichen."""
    results: dict = {"mode": "browser", "tiktok": None, "youtube": None, "instagram": None}
    caption = meta.get("caption") or ""
    title = meta.get("title") or _caption_to_title(caption)
    video = Path(meta.get("video") or "")

    if video.is_file():
        try:
            subprocess.run(
                ["explorer", "/select,", str(video.resolve())],
                check=False,
                timeout=8,
            )
        except OSError:
            pass

    yt_text = f"{title}\n\n{caption}".strip()

    if tiktok:
        try:
            from jam.tiktok_studio import open_upload_in_user_browser

            open_upload_in_user_browser(
                str(meta.get("account") or load_config().get("tiktok_account", "socialmedia.mentor")),
                caption=caption,
                slot=str(meta.get("slot") or "jampulse"),
            )
            results["tiktok"] = {"ok": True, "message": "TikTok Upload geöffnet, Caption in Zwischenablage"}
        except Exception as e:
            _clipboard(caption)
            try:
                webbrowser.open("https://www.tiktok.com/tiktokstudio/upload?from=webapp", new=2)
            except OSError:
                pass
            results["tiktok"] = {"ok": True, "message": f"TikTok geöffnet (Fallback): {e}"[:120]}

    if youtube:
        cfg = load_config()
        _clipboard(yt_text)
        try:
            webbrowser.open(cfg.get("youtube_studio_url") or "https://studio.youtube.com/", new=2)
            webbrowser.open("https://www.youtube.com/upload", new=0)
        except OSError:
            pass
        results["youtube"] = {
            "ok": True,
            "message": "YouTube Studio geöffnet, Titel+Text in Zwischenablage",
        }

    if instagram:
        _clipboard(caption)
        try:
            webbrowser.open("https://www.instagram.com/", new=2)
        except OSError:
            pass
        results["instagram"] = {
            "ok": True,
            "message": "Instagram geöffnet – Reel erstellen, Video + Caption einfügen",
        }

    _write_status({"last": meta, "results": results})
    return results


def _run_assist(script: Path, *, video: Path, caption: str, title: str, auto: bool) -> tuple[bool, str]:
    if not script.is_file():
        return False, f"Skript fehlt: {script.name}"
    env = {
        **os.environ,
        "JAM_PUBLISH_VIDEO": str(video.resolve()),
        "JAM_PUBLISH_CAPTION": caption[:4000],
        "JAM_PUBLISH_TITLE": title[:200],
        "JAM_SOCIAL_AUTO_POST": "1" if auto else "0",
    }
    try:
        proc = subprocess.run(
            [sys.executable, str(script)],
            cwd=str(ROOT),
            env=env,
            timeout=300,
            capture_output=True,
            text=True,
            encoding="utf-8",
            errors="replace",
        )
        detail = (proc.stdout or proc.stderr or "").strip()[-300:]
        return proc.returncode == 0, detail or ("OK" if proc.returncode == 0 else "Fehler")
    except subprocess.TimeoutExpired:
        return False, "Timeout – Browser-Fenster prüfen"
    except OSError as e:
        return False, str(e)[:200]


def publish_playwright(
    meta: dict,
    *,
    tiktok: bool = True,
    youtube: bool = True,
    auto_publish: bool | None = None,
) -> dict:
    cfg = load_config()
    auto = cfg.get("playwright_auto_publish", False) if auto_publish is None else auto_publish
    video = Path(meta.get("video") or meta.get("video_original") or "")
    caption = meta.get("caption") or ""
    title = meta.get("title") or _caption_to_title(caption)
    results: dict = {"mode": "playwright", "tiktok": None, "youtube": None}

    if not video.is_file():
        return {"ok": False, "error": "Video-Datei fehlt", **results}

    if tiktok:
        ok, msg = _run_assist(TIKTOK_ASSIST, video=video, caption=caption, title=title, auto=auto)
        results["tiktok"] = {"ok": ok, "message": msg}

    if youtube:
        ok, msg = _run_assist(YOUTUBE_ASSIST, video=video, caption=caption, title=title, auto=auto)
        results["youtube"] = {"ok": ok, "message": msg}

    payload = {"last": meta, "results": results, "auto_publish": auto}
    _write_status(payload)
    return results


def publish_video(
    video: Path,
    *,
    caption: str = "",
    caption_file: Path | None = None,
    title: str | None = None,
    platforms: tuple[str, ...] = ("tiktok", "youtube"),
    slot: str = "jampulse",
    source: str = "jampulse",
    mode: str | None = None,
) -> dict:
    """Video auf gewählte Plattformen veröffentlichen (vorbereiten + ausführen)."""
    if not video.is_file():
        return {"ok": False, "error": f"Video nicht gefunden: {video}"}

    cap = caption.strip() or _read_caption_file(caption_file)
    if not cap:
        cap = f"{title or 'JamPulse Video'}\n\n{load_config().get('default_tags', '#shorts')}"

    cfg = load_config()
    meta = prepare_post_meta(
        video=video, caption=cap, title=title, slot=slot, source=source
    )

    want_tiktok = "tiktok" in platforms and cfg.get("tiktok_enabled", True)
    want_youtube = "youtube" in platforms and cfg.get("youtube_enabled", True)
    want_instagram = "instagram" in platforms and cfg.get("instagram_enabled", True)
    use_browser = mode == "browser" or (mode is None and cfg.get("use_user_browser", True))

    if use_browser:
        results = publish_browser(
            meta, tiktok=want_tiktok, youtube=want_youtube, instagram=want_instagram
        )
    else:
        results = publish_playwright(
            meta, tiktok=want_tiktok, youtube=want_youtube
        )

    ok = any(
        (results.get(p) or {}).get("ok")
        for p in ("tiktok", "youtube", "instagram")
        if results.get(p) is not None
    )
    return {"ok": ok, "meta": meta, "results": results}


def publish_after_jampulse_job(
    job: dict,
    *,
    platforms: tuple[str, ...] = ("tiktok", "youtube"),
    background: bool = True,
) -> None:
    """Nach JamPulse-Video-Job automatisch posten."""
    video = Path(job.get("local_video") or "")
    caption_path = Path(job.get("caption") or "")
    if not video.is_file():
        return

    cap = _read_caption_file(caption_path) if caption_path.is_file() else ""
    title = (job.get("prompt") or "")[:95]

    def _run() -> None:
        publish_video(
            video,
            caption=cap,
            title=title,
            platforms=platforms,
            slot=f"jampulse-{job.get('id', 'x')[:8]}",
            source="jampulse_frame",
        )

    if background:
        threading.Thread(target=_run, daemon=True).start()
    else:
        _run()


def publish_from_job_id(job_id: str, *, platforms: tuple[str, ...] = ("tiktok", "youtube")) -> dict:
    from jam.pixverse_studio import load_job

    job = load_job(job_id)
    if not job:
        return {"ok": False, "error": "Job nicht gefunden"}
    if job.get("status") != "done":
        return {"ok": False, "error": f"Job nicht fertig ({job.get('status')})"}
    return publish_video(
        Path(job.get("local_video") or ""),
        caption_file=Path(job.get("caption") or ""),
        title=str(job.get("prompt") or "")[:95],
        platforms=platforms,
        slot=f"job-{job_id[:8]}",
        source="jampulse_job",
    )
