"""
Local video/audio transcription using faster-whisper.
100% free, runs on CPU. Supports mp4, mp3, wav, webm, m4a, ogg.
Also supports transcription by URL: downloads audio then transcribes.
"""

import logging
import os
import re
import shutil
import subprocess
import tempfile
import time
from pathlib import Path

logger = logging.getLogger(__name__)

# Lazy-loaded model singleton
_model = None
_model_name = "base"


def _get_model():
    global _model
    if _model is None:
        from faster_whisper import WhisperModel
        logger.info(f"Loading Whisper model '{_model_name}'...")
        t0 = time.time()
        _model = WhisperModel(_model_name, device="cpu", compute_type="int8")
        logger.info(f"Whisper model loaded in {time.time() - t0:.1f}s")
    return _model


def transcribe_file(file_path: str, language: str = None) -> dict:
    """
    Transcribe an audio/video file using Whisper.

    Args:
        file_path: Path to audio/video file
        language: Optional language code (e.g. 'pt', 'en'). Auto-detected if None.

    Returns:
        dict with transcript, segments, language, duration
    """
    file_path = Path(file_path)
    if not file_path.exists():
        return {"success": False, "error": "Arquivo nao encontrado"}

    # Convert to WAV 16kHz mono for best Whisper performance
    wav_path = None
    try:
        wav_path = _convert_to_wav(str(file_path))
        if not wav_path:
            return {"success": False, "error": "Erro ao converter audio. Verifique o formato do arquivo."}

        model = _get_model()

        t0 = time.time()
        kwargs = {"beam_size": 5, "vad_filter": True}
        if language:
            kwargs["language"] = language

        segments_gen, info = model.transcribe(wav_path, **kwargs)

        segments = []
        full_text_parts = []
        for seg in segments_gen:
            segments.append({
                "start": round(seg.start, 2),
                "end": round(seg.end, 2),
                "text": seg.text.strip(),
            })
            full_text_parts.append(seg.text.strip())

        elapsed = time.time() - t0
        full_text = " ".join(full_text_parts)

        logger.info(
            f"Whisper transcribed {info.duration:.0f}s audio in {elapsed:.1f}s "
            f"(lang={info.language}, {len(segments)} segments)"
        )

        return {
            "success": True,
            "transcript": segments,
            "transcript_text": full_text,
            "language": info.language,
            "language_probability": round(info.language_probability, 2),
            "duration": round(info.duration, 1),
            "processing_time": round(elapsed, 1),
            "segments_count": len(segments),
            "word_count": len(full_text.split()),
        }

    except Exception as e:
        logger.error(f"Whisper transcription error: {e}")
        return {"success": False, "error": f"Erro na transcricao: {str(e)[:200]}"}
    finally:
        if wav_path and os.path.exists(wav_path):
            os.unlink(wav_path)


def transcribe_url(url: str, language: str = None) -> dict:
    """
    Download audio from a URL and transcribe with Whisper.
    Tries multiple download methods:
      1. yt-dlp (works for TikTok, some YouTube)
      2. pytubefix with OAuth (YouTube)
      3. ScrapeCreators video download URL (fallback, costs 1 credit)
    Then runs Whisper locally (free).
    """
    platform = _detect_platform(url)
    tmpdir = tempfile.mkdtemp(prefix="whisper_")
    audio_path = None

    try:
        # Step 1: Download audio
        audio_path = _download_audio(url, platform, tmpdir)

        if not audio_path:
            return {
                "success": False,
                "error": "Nao foi possivel baixar o audio do video. Tente fazer upload do arquivo manualmente.",
            }

        # Step 2: Transcribe with Whisper
        result = transcribe_file(audio_path, language=language)
        if result.get("success"):
            result["source"] = "whisper"
            result["platform"] = platform
            result["url"] = url
        return result

    except Exception as e:
        logger.error(f"transcribe_url error: {e}")
        return {"success": False, "error": f"Erro: {str(e)[:200]}"}
    finally:
        shutil.rmtree(tmpdir, ignore_errors=True)


def _detect_platform(url: str) -> str:
    if "tiktok.com" in url:
        return "tiktok"
    if "instagram.com" in url:
        return "instagram"
    if "youtube.com" in url or "youtu.be" in url:
        return "youtube"
    return "unknown"


def _download_audio(url: str, platform: str, tmpdir: str) -> str | None:
    """Try multiple methods to download audio from a video URL."""

    # Method 1: yt-dlp (works for TikTok, Instagram, some YouTube)
    audio = _download_with_ytdlp(url, platform, tmpdir)
    if audio:
        return audio

    # Method 2: pytubefix with OAuth (YouTube only)
    if platform == "youtube":
        audio = _download_with_pytubefix(url, tmpdir)
        if audio:
            return audio

    # Method 3: ScrapeCreators download URL (costs 1 credit but transcript is free)
    audio = _download_with_scrapecreators(url, platform, tmpdir)
    if audio:
        return audio

    return None


def _download_with_ytdlp(url: str, platform: str, tmpdir: str) -> str | None:
    """Download audio using yt-dlp."""
    try:
        import yt_dlp

        output = os.path.join(tmpdir, "audio.%(ext)s")
        opts = {
            "format": "bestaudio/best",
            "outtmpl": output,
            "quiet": True,
            "no_warnings": True,
            "noplaylist": True,
            "socket_timeout": 30,
            "postprocessors": [
                {"key": "FFmpegExtractAudio", "preferredcodec": "mp3"}
            ],
        }

        if platform == "tiktok":
            opts["http_headers"] = {
                "User-Agent": (
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                    "AppleWebKit/537.36 (KHTML, like Gecko) "
                    "Chrome/131.0.0.0 Safari/537.36"
                )
            }

        with yt_dlp.YoutubeDL(opts) as ydl:
            ydl.extract_info(url, download=True)

        # Find the downloaded file
        for f in os.listdir(tmpdir):
            fpath = os.path.join(tmpdir, f)
            if os.path.getsize(fpath) > 0:
                logger.info(f"yt-dlp downloaded: {f} ({os.path.getsize(fpath)} bytes)")
                return fpath

        return None
    except Exception as e:
        logger.debug(f"yt-dlp download failed for {platform}: {e}")
        return None


def _download_with_pytubefix(url: str, tmpdir: str) -> str | None:
    """Download YouTube audio using pytubefix with OAuth."""
    try:
        from backend.services.youtube_auth import yt_auth_manager

        if not yt_auth_manager.is_authenticated:
            logger.debug("pytubefix: no OAuth token, skipping")
            return None

        from pytubefix import YouTube

        token_file = str(Path(__file__).resolve().parent.parent.parent / "data" / "youtube_oauth.json")

        yt = YouTube(
            url,
            client="WEB",
            use_oauth=True,
            allow_oauth_cache=True,
            token_file=token_file,
        )

        # Get audio stream
        stream = (
            yt.streams.filter(only_audio=True, file_extension="mp4")
            .order_by("abr")
            .desc()
            .first()
        )
        if not stream:
            stream = yt.streams.filter(only_audio=True).first()

        if not stream:
            return None

        filepath = stream.download(output_path=tmpdir, filename="yt_audio.mp4")
        if filepath and os.path.exists(filepath) and os.path.getsize(filepath) > 0:
            logger.info(f"pytubefix downloaded: {os.path.getsize(filepath)} bytes")
            return filepath

        return None
    except Exception as e:
        logger.debug(f"pytubefix download failed: {e}")
        return None


def _download_with_scrapecreators(url: str, platform: str, tmpdir: str) -> str | None:
    """Get download URL from ScrapeCreators and download the video (costs 1 credit)."""
    try:
        import requests
        from backend.core.config import settings

        api_key = getattr(settings, "SCRAPECREATORS_API_KEY", None)
        if not api_key:
            return None

        headers = {"x-api-key": api_key}
        download_url = None

        if platform == "tiktok":
            r = requests.get(
                "https://api.scrapecreators.com/v2/tiktok/video",
                params={"url": url},
                headers=headers,
                timeout=30,
            )
            if r.ok:
                data = r.json().get("data", {})
                download_url = (
                    data.get("download_url")
                    or data.get("video_url")
                    or data.get("play_url")
                    or data.get("play")
                )
        elif platform == "instagram":
            r = requests.get(
                "https://api.scrapecreators.com/v1/instagram/post",
                params={"url": url},
                headers=headers,
                timeout=30,
            )
            if r.ok:
                data = r.json().get("data", {})
                download_url = data.get("video_url") or data.get("url")
        elif platform == "youtube":
            # ScrapeCreators doesn't provide YouTube download URLs
            return None

        if not download_url:
            return None

        # Download the actual video file
        logger.info(f"Downloading from ScrapeCreators CDN URL...")
        r = requests.get(download_url, timeout=60, stream=True)
        if r.ok:
            ext = ".mp4"
            fpath = os.path.join(tmpdir, f"sc_video{ext}")
            with open(fpath, "wb") as f:
                for chunk in r.iter_content(chunk_size=8192):
                    f.write(chunk)
            if os.path.getsize(fpath) > 0:
                logger.info(f"ScrapeCreators CDN downloaded: {os.path.getsize(fpath)} bytes")
                return fpath

        return None
    except Exception as e:
        logger.debug(f"ScrapeCreators download failed: {e}")
        return None


def _convert_to_wav(input_path: str) -> str | None:
    """Convert any audio/video to WAV 16kHz mono using ffmpeg."""
    try:
        wav_path = tempfile.mktemp(suffix=".wav")
        result = subprocess.run(
            [
                "ffmpeg", "-y", "-i", input_path,
                "-ar", "16000", "-ac", "1", "-f", "wav",
                wav_path,
            ],
            capture_output=True,
            timeout=120,
        )
        if result.returncode == 0 and os.path.exists(wav_path):
            return wav_path
        logger.error(f"ffmpeg error: {result.stderr.decode()[:200]}")
        return None
    except Exception as e:
        logger.error(f"ffmpeg conversion error: {e}")
        return None
