"""
Kling AI Video Provider (by Kuaishou)

API Docs: https://app.klingai.com/global/dev/document-api/apiReference/model/videoGeneration
Pricing:  ~$0.14/video (5s std) to ~$0.98/video (10s pro)
Auth:     JWT token from Access Key + Secret Key
Endpoint: https://api.klingai.com/v1/videos/text2video

Setup:
  1. Register at https://klingai.com → Developer → Get API credentials
  2. Set KLING_ACCESS_KEY and KLING_SECRET_KEY in .env
"""
import time
import aiohttp
import asyncio
from flask import current_app
from . import BaseVideoProvider


class KlingProvider(BaseVideoProvider):
    """Kling AI text-to-video provider — best price-to-quality ratio."""

    BASE_URL = "https://api.klingai.com/v1"

    def _get_credentials(self):
        from .key_helper import get_provider_key
        ak, sk = get_provider_key("kling", "KLING_ACCESS_KEY", "KLING_SECRET_KEY")
        return ak or "", sk or ""

    def _generate_jwt(self, ak, sk):
        """Generate a JWT token for Kling API authentication."""
        import jwt
        now = int(time.time())
        payload = {
            "iss": ak,
            "exp": now + 1800,
            "nbf": now - 5,
        }
        return jwt.encode(payload, sk, algorithm="HS256")

    async def generate_video(self, prompt: str, duration: int = 5, **kwargs) -> dict:
        ak, sk = self._get_credentials()
        if not ak or not sk:
            return {"status": "error", "error": "Kling API credentials not configured. Set KLING_ACCESS_KEY and KLING_SECRET_KEY in .env"}

        try:
            token = self._generate_jwt(ak, sk)
        except ImportError:
            return {"status": "error", "error": "PyJWT library required. Run: pip install PyJWT"}
        except Exception as e:
            return {"status": "error", "error": f"JWT generation failed: {e}"}

        url = f"{self.BASE_URL}/videos/text2video"
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        }
        # Kling supports 5s or 10s durations
        secs = "10" if duration > 7 else "5"
        # Model: kling-v2-5-turbo (cheapest), kling-v1-6, kling-v2-1
        model = kwargs.get("model", "kling-v2-5-turbo")
        mode = kwargs.get("mode", "std")  # std or pro

        payload = {
            "model_name": model,
            "prompt": prompt,
            "duration": secs,
            "mode": mode,
            "aspect_ratio": "16:9",
        }

        try:
            timeout = aiohttp.ClientTimeout(total=60)
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.post(url, json=payload, headers=headers) as resp:
                    if resp.content_type and "json" in resp.content_type:
                        result = await resp.json()
                    else:
                        text = await resp.text()
                        return {"status": "error", "error": f"Unexpected response ({resp.status}): {text[:300]}"}

                    if resp.status == 200:
                        data = result.get("data", {})
                        task_id = data.get("task_id", "")
                        if not task_id:
                            return {"status": "error", "error": f"No task_id returned: {result}"}
                        return {"status": "processing", "video_id": task_id, "provider": "kling"}
                    else:
                        error_msg = result.get("message", str(result))
                        return {"status": "error", "error": f"Kling API error ({resp.status}): {error_msg}"}
        except asyncio.TimeoutError:
            return {"status": "error", "error": "Request timed out"}
        except aiohttp.ClientError as e:
            return {"status": "error", "error": f"Connection error: {e}"}
        except Exception as e:
            return {"status": "error", "error": f"Unexpected error: {e}"}

    async def check_status(self, task_id: str) -> dict:
        ak, sk = self._get_credentials()
        if not ak or not sk:
            return {"status": "error", "error": "Kling API credentials not configured"}

        try:
            token = self._generate_jwt(ak, sk)
        except Exception as e:
            return {"status": "error", "error": f"JWT error: {e}"}

        url = f"{self.BASE_URL}/videos/text2video/{task_id}"
        headers = {"Authorization": f"Bearer {token}"}

        try:
            timeout = aiohttp.ClientTimeout(total=60)
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(url, headers=headers) as resp:
                    if resp.content_type and "json" in resp.content_type:
                        result = await resp.json()
                    else:
                        return {"status": "error", "error": f"Unexpected response ({resp.status})"}

                    data = result.get("data", {})
                    task_status = data.get("task_status", "")

                    if task_status == "succeed":
                        videos = data.get("task_result", {}).get("videos", [])
                        if videos:
                            video_url = videos[0].get("url", "")
                            return {"status": "completed", "video_url": video_url}
                        return {"status": "error", "error": "No video in result"}
                    elif task_status == "failed":
                        msg = data.get("task_status_msg", "Generation failed")
                        return {"status": "error", "error": msg}
                    else:
                        # processing / submitted / queued
                        return {"status": "processing", "progress": 0}
        except asyncio.TimeoutError:
            return {"status": "error", "error": "Status check timed out"}
        except aiohttp.ClientError as e:
            return {"status": "error", "error": f"Connection error: {e}"}
        except Exception as e:
            return {"status": "error", "error": f"Unexpected error: {e}"}
