# src/pipeline.py
from ..imports import *
from ..modules import *


def get_thumbnails(video_id: str, video_path: str, thumbnails_path: str):
    """
    Extract thumbnails + OCR → persist into DB JSON.
    """
    print(f"video_id=={video_id}\nvideo_path=={video_path}\nthumbnails_path={thumbnails_path}")
    paths = extract_video_frames_unique(video_path, thumbnails_path, video_id=video_id)
    texts = [ocr_image(p) for p in paths]
    thumbnails = {"paths": paths, "texts": texts}
    upsert_video(video_id, thumbnails=thumbnails)
    return thumbnails


class VideoPipeline:
    def __init__(self, video_url=None, video_path=None, force_refresh=False):
        self.video_url = video_url
        self.video_path = video_path

        if self.video_path and not self.video_url:
            self.video_id = generate_video_id(video_path)
        else:
            self.video_url = get_corrected_url(self.video_url)
            self.video_id = get_video_id(self.video_url)

        self.registry = infoRegistry()

        self.info = self.registry.get_video_info(
            url=video_url,
            video_id=self.video_id,
            video_path=self.video_path,
            force_refresh=force_refresh,
        ) or {}

        self.video_info = self.info.get("info") or {}
        self.video_path, _ = self.get_file_path("video_path")

    def download_video(self):
        return VideoDownloader(
            url=self.video_url,
            registry=self.registry,
            download_video=True,
        )

    def get_file_path(self, key: str):
        """
        Safely fetch a path from self.video_info and tell whether it exists on disk.
        """
        path = self.video_info.get(key)
        if not path:
            logger.info(f"{key} is empty or missing in video_info")
            return None, False

        exists = os.path.isfile(path)
        isexist = "exists" if exists else "does not exist"
        logger.info(f"{key} is {path} and {isexist}")
        return path, exists

    # === AUDIO ===
    def ensure_audio(self):
        record = get_video_record(self.video_id) or {}

        audio_path, exists = self.get_file_path("audio_path")
        if record and audio_path and exists:
            audio_format = audio_path.split(".")[-1]
            return audio_path, audio_format

        # Need to (re)create audio
        self.download_video()
        video_path, v_exists = self.get_file_path("video_path")
        if not video_path or not v_exists:
            raise RuntimeError(f"Video file not found for {self.video_id}")

        # Choose a sensible default audio file name if missing
        if not audio_path:
            base, _ = os.path.splitext(video_path)
            audio_path = base + ".wav"

        os.system(
            f"ffmpeg -y -i {video_path} -vn -acodec pcm_s16le -ar 16000 -ac 1 {audio_path}"
        )
        audio_format = audio_path.split(".")[-1]

        upsert_video(self.video_id, audio_path=audio_path, audio_format=audio_format)
        return audio_path, audio_format

    # === WHISPER ===
    def get_whisper(self):
        record = get_video_record(self.video_id) or {}
        whisper_result = record.get("whisper")

        if record and whisper_result:
            return whisper_result

        audio_path, fmt = self.ensure_audio()
        result = whisper_transcribe(audio_path)

        upsert_video(self.video_id, whisper=result)
        return result

    # === CAPTIONS ===
    def get_captions(self):
        record = get_video_record(self.video_id) or {}
        if record and record.get("captions"):
            return record["captions"]

        whisper = self.get_whisper()
        captions = [
            {"start": seg["start"], "end": seg["end"], "text": seg["text"]}
            for seg in whisper.get("segments", [])
        ]

        upsert_video(self.video_id, captions=captions)
        return captions

    # === METADATA ===
    def get_metadata(self):
        record = get_video_record(self.video_id) or {}
        if record and record.get("metadata"):
            return record["metadata"]

        whisper = self.get_whisper()
        captions = self.get_captions()

        text_blob = " ".join([whisper.get("text", "")] + [c["text"] for c in captions])
        title = (
            self.info.get("title")
            or self.video_info.get("title")
            or text_blob[:50]
            or "Untitled"
        )
        summary = get_summarizer_summary(text=text_blob)

        keywords = self.info.get("keywords") or self.video_info.get("keywords") or []
        tags = self.info.get("tags") or self.video_info.get("tags") or []
        extracted_keywords = get_extracted_keywords(text=text_blob) or []
        keywords = make_list(keywords + tags + extracted_keywords)

        category = classify_category(make_list(keywords),title=title,description=summary)
        if len(keywords) >= 10:
            keywords = keywords[:10]

        metadata = {
            "title": title,
            "summary": summary,
            "category": category,
            "keywords": keywords,
        }

        upsert_video(self.video_id, metadata=metadata)
        return metadata

    # === THUMBNAILS ===
    def get_thumbnails(self):
        record = get_video_record(self.video_id) or {}
        if record and record.get("thumbnails"):
            return record["thumbnails"]

        self.download_video()
        video_id = self.video_id
        video_path = self.video_info.get("video_path")
        thumbnails_dir = self.video_info.get("thumbnails_directory")

        thumbnails = get_thumbnails(video_id, video_path, thumbnails_dir)
        upsert_video(self.video_id, thumbnails=thumbnails)
        return thumbnails

    # === SEODATA ===
    def get_seodata(self):
        record = get_video_record(self.video_id) or {}
        if record and record.get("seodata"):
            return record["seodata"]

        dl = VideoDownloader(url=self.video_url, download_video=True)
        whisper_result = self.get_whisper()
        captions = self.get_captions()

        thumbnails = self.get_thumbnails()
        thumbnails_dir = self.video_info.get("thumbnails_directory")
        thumbnails_paths = thumbnails.get("paths")

        metadata = self.get_metadata()
        title = metadata.get("title")
        summary = metadata.get("summary")
        keywords = metadata.get("keywords")
        description = metadata.get("description", summary)

        video_id = self.video_id
        video_path = self.video_info.get("video_path")
        if not (video_path and os.path.isfile(video_path)):
            file_map = get_file_map(video_path, types="video")
            video_paths = file_map.get("video")
            if video_paths:
                video_path = video_paths[0]

        audio_path = self.video_info.get("audio_path")
        if not (audio_path and os.path.isfile(audio_path)):
            file_map = get_file_map(video_path, types="audio")
            audio_paths = file_map.get("audio")
            if audio_paths:
                audio_path = audio_paths[0]

        seodata = get_seo_data(
            video_path=video_path,
            filename=video_id,
            title=title,
            summary=summary,
            description=description,
            keywords=keywords,
            thumbnails_dir=thumbnails_dir,
            thumbnail_paths=thumbnails_paths,
            whisper_result=whisper_result,
            audio_path=audio_path,
            domain="clownworld.biz",
        )

        # Store raw seodata (filesystem paths), frontend will get URL-converted
        upsert_video(self.video_id, seodata=seodata)
        return seodata

    # === AGGREGATED ===
    def get_aggregated_data(self):
        record = get_video_record(self.video_id) or {}
        if record and record.get("aggregated"):
            return record["aggregated"]

        video_info = record.get("info") or {}
        directory = video_info.get("directory")
        aggregated = aggregate_from_base_dir(directory=directory)

        upsert_video(self.video_id, aggregated=aggregated)
        return aggregated

    # === METATAGS / META.JSON ===
    def get_meta_tags(self):
        """
        Build meta tags, persist them, and return a version where
        all filesystem/static paths are converted to public URLs.
        """
        record = get_video_record(self.video_id) or {}
        if record and record.get("metatags"):
            return record["metatags"]

        video_info = record.get("info") or {}
        directory = video_info.get("directory")
        meta_file_path = os.path.join(directory, "meta.json")

        data = self.get_all_data()
        base_url = "https://clownworld.biz"

        metadict = build_seo_meta_from_result(data, base_url=base_url)

        # Make sure all paths inside metadict are URL-style before saving
        metadict_public = convert_paths_to_urls(metadict, base_url=base_url)

        upsert_video(self.video_id, metatags=metadict_public)
        safe_dump_to_json(data=metadict_public, file_path=meta_file_path)
        return metadict_public

    # === INFO / ALL ===
    def get_info(self):
        return get_video_record(self.video_id, hide_audio=True) or {}

    def get_all_data(self):
        return {
            "info": self.get_info(),
            "whisper": self.get_whisper(),
            "captions": self.get_captions(),
            "metadata": self.get_metadata(),
            "thumbnails": self.get_thumbnails(),
            "seodata": self.get_seodata(),
            "aggregated": self.get_aggregated_data(),
        }

    def get_all(self):
        return {
            "info": self.get_info(),
            "whisper": self.get_whisper(),
            "captions": self.get_captions(),
            "metadata": self.get_metadata(),
            "thumbnails": self.get_thumbnails(),
            "seodata": self.get_seodata(),
            "aggregated": self.get_aggregated_data(),
            "metatags": self.get_meta_tags(),
        }


def get_pipeline_data(
    url: str,
    key: str | None = None,
    base_url: str = "https://clownworld.biz",
):
    """
    Public API used by Flask route.

    ANYTHING returned to the client is run through convert_paths_to_urls,
    so React always sees proper URLs, never raw filesystem paths.
    """
    p = VideoPipeline(url)

    pipeline_js = {
        "info": p.get_info,
        "download": p.download_video,
        "download_video": p.download_video,
        "extract_audio": p.ensure_audio,
        "whisper": p.get_whisper,
        "captions": p.get_captions,
        "metadata": p.get_metadata,
        "thumbnails": p.get_thumbnails,
        "seodata": p.get_seodata,
        "metatags": p.get_meta_tags,
        "get_all": p.get_all,
    }

    def _call_and_convert(func):
        result = func()
        return convert_paths_to_urls(result, base_url=base_url)

    if key:
        func = pipeline_js.get(key)
        if not func:
            # Optional: raise or just return an error structure
            return {"error": f"Unknown key '{key}'"}
        return _call_and_convert(func)

    # Default: full pipeline
    return _call_and_convert(p.get_all)
