"""Free-tier AI video provider handoff specs.

This module does not automate paid video generation. It creates manual browser
handoff packets for free/freemium AI video tools, then keeps final assembly local.
The intent is a hybrid workflow: realistic short AI clips from free quotas plus
local mechanism animation/captions/FFmpeg composition.
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from autoshorts.script_drafts import _slug

FREE_AI_VIDEO_PROVIDERS: dict[str, dict[str, Any]] = {
    "pixverse": {
        "display_name": "PixVerse",
        "url": "https://app.pixverse.ai/",
        "source_url": "https://app.pixverse.ai/",
        "researched_evidence": "App page showed 90 credits with daily refresh and signup prompt for free credits.",
        "cost_policy": "free_tier_only_no_paid_topups",
        "automation_mode": "manual_browser_handoff",
        "free_tier": {
            "daily_refresh_credits": 90,
            "signup_required": True,
            "best_use": "realistic text/image-to-video short clips",
        },
        "strengths": ["realistic clips", "daily free quota", "templates", "image-to-video"],
        "risks": ["terms and quotas can change", "manual account/login required", "possible watermark depending export path"],
    },
    "pika": {
        "display_name": "Pika",
        "url": "https://pika.art/",
        "source_url": "https://pika.art/pricing",
        "researched_evidence": "Pricing page showed Basic $0 with 80 monthly video credits, Pika 2.5 at 480p only, no-watermark downloads, and commercial use.",
        "cost_policy": "free_tier_only_no_paid_topups",
        "automation_mode": "manual_browser_handoff",
        "free_tier": {
            "monthly_credits": 80,
            "max_resolution": "480p",
            "text_to_video_5s_credits": 12,
            "watermark_free_claimed": True,
            "commercial_use_claimed": True,
            "signup_required": True,
        },
        "strengths": ["no-watermark claim", "commercial-use claim", "good fallback for 5s shots"],
        "risks": ["low 480p free resolution", "monthly quota is small", "manual account/login required"],
    },
    "capcut": {
        "display_name": "CapCut AI Video Maker",
        "url": "https://www.capcut.com/tools/ai-video-generator",
        "source_url": "https://www.capcut.com/tools/ai-video-generator",
        "researched_evidence": "CapCut tool page describes a free AI video generator and says final videos can be exported in HD quality for free.",
        "cost_policy": "free_tier_only_no_paid_topups",
        "automation_mode": "manual_browser_handoff",
        "free_tier": {
            "hd_export_claimed": True,
            "credit_amount_publicly_clear": False,
            "best_use": "editorial assembly, templates, captions, quick drafts",
            "signup_required": True,
        },
        "strengths": ["HD export claim", "editing/captions/templates", "easy manual polishing"],
        "risks": ["free quota not clearly exposed on public page", "may upsell Pro assets", "manual export required"],
    },
    "hailuo": {
        "display_name": "Hailuo AI",
        "url": "https://hailuoai.video/",
        "source_url": "https://hailuoai.video/",
        "researched_evidence": "Public generator page exposed 768p/6s generation controls and a visible 25-credit create cost, suitable only if free account credits are available.",
        "cost_policy": "free_tier_only_no_paid_topups",
        "automation_mode": "manual_browser_handoff",
        "free_tier": {
            "default_visible_generation_cost_credits": 25,
            "signup_required": True,
            "use_only_existing_free_credits": True,
        },
        "strengths": ["realistic generator", "768p/6s option visible"],
        "risks": ["do not buy credits", "free quota may vary", "user explicitly wants no paid Hailuo credits"],
    },
}

PAID_OR_UNSUITABLE_FOR_FREE_FIRST = {"runway", "luma", "kling", "veo", "sora"}
AI_VIDEO_SCENE_MODES = {"cinematic_ai_video"}
LOCAL_SCENE_MODES = {"mechanism_animation", "kinetic_text_overlay", "screen_recording_simulation", "animated_card"}


def recommended_provider_order(asset_mode: str) -> list[str]:
    """Return provider preference for a scene mode under free-tier constraints."""
    if asset_mode == "cinematic_ai_video":
        return ["pixverse", "pika", "capcut", "hailuo"]
    if asset_mode == "mechanism_animation":
        return ["local_renderer", "capcut"]
    return ["local_renderer"]


def _local_render_jobs(production_jobs: dict[str, Any]) -> list[dict[str, Any]]:
    return [job for job in production_jobs["jobs"] if job["provider"] in {"local_renderer", "local_ffmpeg"}]


def _duration_for_free_ai(job: dict[str, Any]) -> float:
    # Most free-tier AI video tools are strongest around 5s clips. Longer scenes
    # should be split later; the current pilot only needs two short cinematic clips.
    return min(5.0, float(job["duration_seconds"]))


def _provider_notes(provider_id: str) -> dict[str, Any]:
    provider = FREE_AI_VIDEO_PROVIDERS[provider_id]
    return {
        "provider": provider_id,
        "display_name": provider["display_name"],
        "url": provider["url"],
        "free_tier": provider["free_tier"],
        "risks": provider["risks"],
    }


def _ai_video_job(job: dict[str, Any]) -> dict[str, Any]:
    provider_order = recommended_provider_order(job["asset_mode"])
    return {
        "job_id": f"{job['scene_id']}_free_ai_video_handoff",
        "scene_id": job["scene_id"],
        "asset_mode": job["asset_mode"],
        "status": "manual_generation_required",
        "duration_seconds": _duration_for_free_ai(job),
        "aspect_ratio": "9:16",
        "preferred_resolution": "480p_or_best_free_available",
        "provider_order": provider_order,
        "providers": [_provider_notes(provider_id) for provider_id in provider_order],
        "prompt": _free_ai_prompt(job),
        "negative_prompt": job["negative_prompt"],
        "overlay_text": job["overlay_text"],
        "free_tier_guardrails": {
            "do_not_buy_credits": True,
            "use_only_free_daily_or_monthly_quota": True,
            "avoid_pro_templates_or_paid_assets": True,
            "export_without_baked_captions": True,
            "final_captions_added_locally": True,
        },
        "manual_steps": [
            "Open the first available provider in provider_order.",
            "Use text-to-video or image-to-video with the prompt below; choose vertical 9:16 if available.",
            "Set duration to the requested scene duration or the nearest free option, usually 5s.",
            "Do not buy credits, subscribe, or select paid-only models/templates.",
            "Download the clip, then place it under data/imported_ai_clips/<video_id>/<scene_id>.mp4 for local assembly.",
        ],
        "expected_clip_path": f"data/imported_ai_clips/{{video_id}}/{job['scene_id']}.mp4",
    }


def _free_ai_prompt(job: dict[str, Any]) -> str:
    intent = job.get("source_prompt", "")
    for marker in [
        "Use local procedural animation/parallax rather than paid AI-video credits; keep captions renderer-overlay only.",
        "Use local procedural animation/parallax rather than paid AI-video credits",
    ]:
        intent = intent.replace(marker, "")
    intent = intent.replace("Vertical 9:16 cinematic-looking local motion scene,", "")
    intent = " ".join(intent.split())
    return (
        f"Vertical 9:16 realistic cinematic short video. {intent} "
        "No captions, no readable text, no logos, no watermarks. Leave clean negative space in the lower third for captions. "
        "The clip should feel like real b-roll for a mechanism explainer, not a slideshow."
    )


def build_free_ai_video_handoff(production_jobs: dict[str, Any]) -> dict[str, Any]:
    """Build a manual free-tier AI video handoff while keeping local assembly."""
    local_jobs = _local_render_jobs(production_jobs)
    ai_jobs = [job for job in local_jobs if job["asset_mode"] in AI_VIDEO_SCENE_MODES]
    fallback_local_jobs = [job for job in local_jobs if job["asset_mode"] not in AI_VIDEO_SCENE_MODES]
    return {
        "schema_version": "free_ai_video_handoff.v1",
        "video": production_jobs["video"],
        "budget_policy": {
            "paid_topups_allowed": False,
            "paid_subscriptions_allowed": False,
            "allowed_strategy": "free_tier_manual_generation_plus_local_assembly",
            "local_fallback_required": True,
        },
        "researched_sources": [
            {"provider": key, "source_url": value["source_url"], "evidence": value["researched_evidence"]}
            for key, value in FREE_AI_VIDEO_PROVIDERS.items()
        ],
        "hybrid_strategy": {
            "realistic_clip_source": "free_tier_ai_video_tools_manual_handoff",
            "mechanism_explainer_source": "local_renderer",
            "captions": "local_kinetic_renderer_overlay",
            "final_assembly": "local_ffmpeg",
        },
        "ai_video_jobs": [_ai_video_job(job) for job in ai_jobs],
        "local_jobs": [
            {
                "scene_id": job["scene_id"],
                "asset_mode": job["asset_mode"],
                "provider": job["provider"],
                "execution_mode": job["execution_mode"],
                "duration_seconds": job["duration_seconds"],
                "role": "local_mechanism_or_caption_layer",
            }
            for job in fallback_local_jobs
        ],
    }


def _handoff_filename(video: dict[str, Any]) -> str:
    title_slug = _slug(video["title"])
    video_id = video["id"]
    if video_id.endswith(title_slug):
        return f"{video_id}.json"
    return f"{video_id}-{title_slug}.json"


def write_free_ai_video_handoffs(production_jobs_list: list[dict[str, Any]], output_dir: Path) -> list[Path]:
    """Write free-tier AI video handoff packets as JSON files."""
    output_dir.mkdir(parents=True, exist_ok=True)
    paths: list[Path] = []
    for production_jobs in production_jobs_list:
        handoff = build_free_ai_video_handoff(production_jobs)
        path = output_dir / _handoff_filename(handoff["video"])
        path.write_text(json.dumps(handoff, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
        paths.append(path)
    return paths
