#!/usr/bin/env python3
"""Search/download Pexels videos with caching, candidate review, and provenance.

NOTE: `scripts/stock_media.py` supersedes this script. It searches every
configured provider at once, deduplicates the results, builds a contact sheet
so the choice is visual, and verifies each download with ffprobe:

    python scripts/stock_media.py "запрос" --kind video --providers pexels \n      --orientation portrait --sheet candidates.jpg

This one is kept because existing project scripts call it."""
from __future__ import annotations

import argparse
import hashlib
import json
import sys
import time
from datetime import datetime, timezone
from pathlib import Path

import requests

from skill_config import SKILL_ROOT, require_secret


def cached_search(query: str, orientation: str, count: int, cache_dir: Path, key: str) -> dict:
    params = {"query": query, "orientation": orientation, "size": "medium", "per_page": min(max(count * 3, 3), 80)}
    signature = json.dumps(params, ensure_ascii=False, sort_keys=True)
    cache = cache_dir / f"{hashlib.sha256(signature.encode()).hexdigest()}.json"
    cache.parent.mkdir(parents=True, exist_ok=True)
    if cache.exists() and time.time() - cache.stat().st_mtime < 86400:
        return json.loads(cache.read_text(encoding="utf-8"))
    response = requests.get(
        "https://api.pexels.com/v1/videos/search",
        headers={"Authorization": key, "User-Agent": "AI-Pro-Video-Skill/3"},
        params=params,
        timeout=30,
    )
    response.raise_for_status()
    data = response.json()
    cache.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
    return data


def choose_file(video: dict, orientation: str) -> dict | None:
    files = [item for item in video.get("video_files", []) if item.get("link")]
    if orientation == "portrait":
        preferred = [item for item in files if item.get("height", 0) >= item.get("width", 0)]
    elif orientation == "landscape":
        preferred = [item for item in files if item.get("width", 0) >= item.get("height", 0)]
    else:
        preferred = files
    pool = preferred or files
    return max(pool, key=lambda item: min(item.get("width", 0), 1920) * min(item.get("height", 0), 1920), default=None)


def download(url: str, out: Path) -> None:
    out.parent.mkdir(parents=True, exist_ok=True)
    with requests.get(url, stream=True, timeout=180) as response:
        response.raise_for_status()
        with out.open("wb") as handle:
            for chunk in response.iter_content(1024 * 1024):
                if chunk:
                    handle.write(chunk)

def merge_manifest(path: Path, new_items: list[dict]) -> list[dict]:
    existing = []
    if path.exists():
        existing = json.loads(path.read_text(encoding="utf-8"))
    merged = {(item.get("provider"), item.get("id")): item for item in existing}
    for item in new_items:
        merged[(item.get("provider"), item.get("id"))] = item
    return sorted(merged.values(), key=lambda item: (str(item.get("provider")), int(item.get("id") or 0)))


def main() -> None:
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8", errors="replace")
    parser = argparse.ArgumentParser()
    parser.add_argument("query")
    parser.add_argument("--count", type=int, default=5)
    parser.add_argument("--orientation", choices=["portrait", "landscape", "square"], default="portrait")
    parser.add_argument("--out", default="project/assets/stock/pexels")
    parser.add_argument("--cache", default=str(SKILL_ROOT / "cache" / "pexels"))
    parser.add_argument("--search-only", action="store_true")
    parser.add_argument("--ids", help="Comma-separated Pexels IDs to download after review")
    args = parser.parse_args()
    key = require_secret("PEXELS_API_KEY")
    data = cached_search(args.query, args.orientation, args.count, Path(args.cache), key)
    allowed = {int(value) for value in args.ids.split(",")} if args.ids else None
    candidates = []
    manifest = []
    outdir = Path(args.out)
    for video in data.get("videos", []):
        selected = choose_file(video, args.orientation)
        if not selected:
            continue
        candidate = {
            "provider": "pexels",
            "id": video.get("id"),
            "duration": video.get("duration"),
            "width": selected.get("width"),
            "height": selected.get("height"),
            "source_page": video.get("url"),
            "creator": video.get("user", {}).get("name"),
        }
        candidates.append(candidate)
        if not args.search_only and (allowed is None or video.get("id") in allowed):
            out = outdir / f"pexels_{video.get('id')}.mp4"
            download(selected["link"], out)
            manifest.append({
                **candidate,
                "local_path": str(out),
                "license": "Pexels License",
                "query": args.query,
                "downloaded_at": datetime.now(timezone.utc).isoformat(),
                "attribution": f"Video by {candidate['creator']} on Pexels",
            })
        if len(candidates) >= args.count:
            break
    if not args.search_only:
        outdir.mkdir(parents=True, exist_ok=True)
        manifest_path = outdir / "manifest.json"
        merged = merge_manifest(manifest_path, manifest)
        manifest_path.write_text(json.dumps(merged, ensure_ascii=False, indent=2), encoding="utf-8")
    print(json.dumps({"query": args.query, "candidates": candidates, "downloaded": manifest}, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
