"""Push project metadata to gnommoweb (the review app).

Usage:
  gnommo push -p video1                    # push to local gnommoweb
  gnommo push -p video1 --prod             # push to production gnommoweb
  gnommo push -p short_pixelated_universe  # push a short project
  gnommo push -p myproject --force         # force push, overwrite server

POSTs the project metadata to gnommoweb's POST /api/projects/push.

Configuration (from .env or environment):
  GNOMMOWEB_URL           Base URL for local dev (e.g. http://localhost:3001)
  GNOMMOWEB_API_KEY       Bearer token for local (CONTENT_API_KEY)
  GNOMMOWEB_PROD_URL      Base URL for production (e.g. https://glitch.university)
  GNOMMOWEB_PROD_API_KEY  Bearer token for production (CONTENT_API_KEY)
"""

import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path

try:
    import requests
except ImportError:
    print(
        "Error: 'requests' package is required. Run: pip install requests",
        file=sys.stderr,
    )
    sys.exit(1)

SYNC_FILE_LOCAL = ".gnommo_sync.json"
SYNC_FILE_PROD = ".gnommo_sync.prod.json"


def _sync_file(prod: bool) -> str:
    return SYNC_FILE_PROD if prod else SYNC_FILE_LOCAL


def _load_env_file():
    env_path = Path(__file__).parent.parent / ".env"
    if not env_path.exists():
        return
    with open(env_path) as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith("#") or "=" not in line:
                continue
            key, _, value = line.partition("=")
            key = key.strip()
            value = value.strip().strip('"').strip("'")
            if key not in os.environ:
                os.environ[key] = value


def _read_sync(project_path: Path, prod: bool = False) -> dict:
    sync_file = project_path / _sync_file(prod)
    if sync_file.exists():
        with open(sync_file) as f:
            return json.load(f)
    return {}


def _write_sync(project_path: Path, data: dict, prod: bool = False):
    with open(project_path / _sync_file(prod), "w") as f:
        json.dump(data, f, indent=2)


def cmd_push(
    project_path: Path, verbose: bool = False, force: bool = False, prod: bool = False
) -> int:
    _load_env_file()

    project_file = project_path / "project.json"
    if not project_file.exists():
        print(f"Error: {project_file} not found", file=sys.stderr)
        return 1

    with open(project_file) as f:
        project = json.load(f)

    project_id = project.get("id")
    name = project.get("name")
    if not project_id or not name:
        print("Error: project.json must have 'id' and 'name' fields.", file=sys.stderr)
        return 1

    return _push_gnommoweb(project, project_path, verbose, force, prod)


# ── gnommoweb POST /api/projects/push ─────────────────────────────────────────


def _push_gnommoweb(
    project: dict, project_path: Path, verbose: bool, force: bool, prod: bool
) -> int:
    # --prod selects the production gnommoweb instance; without it, local dev.
    if prod:
        api_url = os.environ.get("GNOMMOWEB_PROD_URL", "").rstrip("/")
        api_key = os.environ.get("GNOMMOWEB_PROD_API_KEY", "")
        url_var, key_var = "GNOMMOWEB_PROD_URL", "GNOMMOWEB_PROD_API_KEY"
    else:
        api_url = os.environ.get("GNOMMOWEB_URL", "").rstrip("/")
        api_key = os.environ.get("GNOMMOWEB_API_KEY", "")
        url_var, key_var = "GNOMMOWEB_URL", "GNOMMOWEB_API_KEY"
    if not api_url:
        print(f"Error: {url_var} is not set.", file=sys.stderr)
        return 1
    if not api_key:
        print(f"Error: {key_var} is not set.", file=sys.stderr)
        return 1

    if verbose:
        target = "production" if prod else "local"
        print(f"  → gnommoweb {target}: {api_url}")

    project_id = project["id"]
    parent_project = project.get("parent_project")

    if parent_project:
        payload = _build_short_payload(project, project_path, verbose)
    else:
        payload = _build_parent_payload(project, project_path, verbose)

    if verbose:
        kind = "short" if parent_project else "parent video"
        print(f"Pushing {project_id} ({kind}) to {api_url}")

    try:
        r = requests.post(
            f"{api_url}/api/projects/push",
            json=payload,
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=30,
        )
    except requests.exceptions.ConnectionError:
        print(f"✗ Could not connect to {api_url}")
        return 1

    if not r.ok:
        try:
            body = r.json()
        except Exception:
            body = r.text[:500]
        print(f"✗ Server returned {r.status_code}: {body}")
        return 1

    result = r.json()
    server_updated_at = result.get("server_updated_at")

    now_iso = datetime.now(tz=timezone.utc).isoformat(timespec="seconds")
    existing_sync = _read_sync(project_path, prod=prod)
    _write_sync(
        project_path,
        {
            **existing_sync,
            "last_pushed_at": now_iso,
            "server_updated_at": server_updated_at,
        },
        prod=prod,
    )

    asset = result.get("asset", {})
    if result.get("type") == "short":
        print(f"✓ {project_id} → gn_asset #{asset.get('id')} [{asset.get('status')}]")
        if result.get("task_created"):
            print(f"  task #{result['task_id']} created")
    else:
        print(f"✓ {project_id} → gn_asset #{asset.get('id')} ({asset.get('name')})")
        if verbose:
            script_len = len(asset.get("script") or "")
            print(
                f"  server.script: {script_len} chars | fps={asset.get('fps')} res={asset.get('resolution')}"
            )

    return 0


def _build_parent_payload(project: dict, project_path: Path, verbose: bool) -> dict:
    script_content = None
    manuscript_str = project.get("manuscript")
    if manuscript_str:
        manuscript_path = project_path / manuscript_str
        if manuscript_path.exists():
            try:
                script_content = manuscript_path.read_text(encoding="utf-8")
            except UnicodeDecodeError:
                script_content = manuscript_path.read_text(encoding="latin-1")
                print(f"  Warning: manuscript is not UTF-8, read as latin-1")
            print(f"  manuscript: {len(script_content)} chars")
        else:
            print(f"  Warning: manuscript not found: {manuscript_path}")
    else:
        if verbose:
            print(f"  no manuscript field in project.json")

    return {
        "project_id": project["id"],
        "name": project["name"],
        "description": project.get("description"),
        "course": project.get("course"),
        "coursecode": project.get("coursecode"),
        "script_content": script_content,
        "resolution": project.get("resolution"),
        "fps": project.get("fps"),
        "duration_seconds": project.get("duration_seconds"),
        "hook": project.get("hook"),
        "platform_targets": project.get("platform_targets"),
        "status": project.get("status"),
        "youtube_url": project.get("youtube_url"),
        "shorts": project.get("shorts", []),
    }


def _build_short_payload(project: dict, project_path: Path, verbose: bool) -> dict:
    script_content = None
    script_path_str = project.get("script")
    if script_path_str:
        script_path = project_path / script_path_str
        if script_path.exists():
            script_content = script_path.read_text()
            if verbose:
                print(f"  Read script: {script_path} ({len(script_content)} chars)")
        else:
            print(f"  Warning: script file not found: {script_path}", file=sys.stderr)

    return {
        "project_id": project["id"],
        "name": project["name"],
        "description": project.get("description"),
        "course": project.get("course"),
        "parent_project": project["parent_project"],
        "hook": project.get("hook"),
        "script_content": script_content,
        "platform_targets": project.get("platform_targets", ["youtube"]),
        "resolution": project.get("resolution"),
        "fps": project.get("fps"),
        "duration_seconds": project.get("duration_seconds"),
    }
