from ..imports import *
from .manager import *
import os
import json
from abstract_utilities.read_write_utils import read_from_file, write_to_file
from abstract_utilities.list_utils import make_list
from abstract_utilities.path_utils import makeAllDirs
from abstract_utilities import is_file,is_media_type
import logging
from ....raw_imports.videoDownloader import *
from .routes import *
def get_text(
    *args,
    text=None,
    url=None,
    file_path=None,
    audio_path=None,
    video_url=None,
    video_path=None,
    video_id=None,
    data_url=None,
    **kwargs
):
    # 1. Explicit text
    if text:
        if video_id:
            db_upsert(video_id, {"text": text})
        return text

    # 2. Audio/video → whisper
    if audio_path or video_url or video_path:
        text = get_whisper_text(
            *args,
            audio_path=audio_path,
            video_url=video_url,
            video_path=video_path,
            **kwargs
        )
        if video_id and text:
            db_upsert(video_id, {"whisper": {"text": text}})
        return text

    # 3. URL / file ingestion
    if url or file_path:
        filename = None
        if file_path:
            basename = os.path.basename(file_path)
            filename, ext = os.path.splitext(basename)
        else:
            domain = urlManager(url).domain
            logger.info(domain)
            filename, ext = os.path.splitext(domain)
            basename = f"{filename}.json"

        save_file = os.path.join(DEFAULT_DOCUMENTS_ROOT, basename)
        text = get_soup_text(url) or read_file_as_text(file_path)

        # Mirror in registry as cache
        info = get_infoRegistry().add_file(
            file_path=file_path or save_file,
            url=url,
            video_id=video_id,
            data_url=data_url
        )
        safe_dump_to_file(data={filename: text}, file_path=save_file)

        # DB as single source of truth
        if video_id and text:
            db_upsert(video_id, {"info": info, "text": text})

        if text and info.get("text_path"):
            write_to_file(info["text_path"], text)
        return text

    # 4. Last chance → DB only
    if video_id:
        rec = db_get(video_id)
        if rec and rec.info:
            return rec.info.get("text")

    return None

def get_soup_text(url):
    soup = get_soup(url)
    return soup.text

def get_video_info_spec(video_url=None,video_path=None,key =None,download=None,force_refresh=False
        ):
    if not video_path and not video_url or (video_path and not is_file(video_path) and not video_url):
        return
    if video_path and not video_url:
        video_id = generate_video_id(video_path)
    else:
        video_url = get_corrected_url(video_url)
        video_id = get_video_id(video_url)
    registry = infoRegistry()
    info = registry.get_video_info(
            url=video_url,
            video_id=video_id,
            video_path=video_path,
            force_refresh=force_refresh
            ) or {}
    video_info = info.get('info')
    if video_url and (not video_path or (video_path and not is_file(video_path))):
        video_mgr = VideoDownloader(
            url=video_url,
            download_video=True
            )
        video_info =  get_info_from_mgr(video_mgr)
    if video_info or (video_path and is_file(video_path)) and is_media_type(video_path, categories=['video']):
        if key:
            return video_info.get(key)
    return video_info
def get_args_kwargs(req):
    """
    Extracts positional args and keyword args from a JSON request.
    Client should send:
        {
            "args": [arg1, arg2, ...],
            "kw1": "val1",
            "kw2": "val2"
        }
    Returns:
        tuple: (args_list, kwargs_dict)
    """
    data = req.get_json(force=True) or {}
    args = data.pop("args", [])   # safely remove and default to list
    if not isinstance(args, (list, tuple)):
        raise ValueError(f"Expected 'args' to be list/tuple, got {type(args)}")
    return args, data
def extract_audio_from_video(video_path: str, audio_path: str = None):
    """Extract audio from a video file using moviepy."""
    if audio_path == None:
        video_directory = os.path.dirname(video_path)
        audio_path = video_directory
    if os.path.isdir(audio_path):
        audio_path = os.path.join(audio_path,'audio.wav')
    try:
        logger.info(f"Extracting audio from {video_path} to {audio_path}")
        video = mp.VideoFileClip(video_path)
        video.audio.write_audiofile(audio_path)
        video.close()
        if not os.path.exists(audio_path):
            raise FileNotFoundError(f"Audio file {audio_path} was not created.")
        logger.info(f"Audio extracted successfully: {audio_path}")
        return audio_path
    except Exception as e:
        logger.error(f"Error extracting audio from {video_path}: {e}")
        return None
def get_schema_paths(
    *args,
    video_url=None,
    video_path=None,
    video_info=None,
    **kwargs
    ):
    if video_info and isinstance(video_info,dict) and video_info.get('schema_paths'):
        return video_info.get('schema_paths')
    schema_paths = get_video_info_spec(
        video_url=video_url,
        video_path=video_path,
        key = 'schema_paths'
        )
    return schema_paths
def get_whisper_video_info(
    *args,
    video_url=None,
    video_path=None,
    video_info=None,
    **kwargs
    ):
    if video_info and isinstance(video_info,dict) and video_info.get('schema_paths'):
        video_path = video_info.get('video_path')
    video_info = get_video_info(
        video_url=video_url,
        video_path=video_path,
        download=True
        )
    return video_info
def get_whisper_audio_path(
    *args,
    audio_path=None,
    video_url=None,
    video_path=None,
    video_info=None,
    **kwargs
    ):
    if audio_path and os.path.isfile(audio_path):
        return audio_path
    video_info = get_whisper_video_info(
            video_url=video_url,
            video_path=video_path,
            video_info=video_info
            )

    video_path = video_path or video_info.get('video_path')
    audio_path = audio_path or video_info.get('audio_path')
    extract_audio_from_video(
            video_path=video_path,
            audio_path=audio_path
            )
    return audio_path
def get_whisper_video_path(
        *args,
        video_url=None,
        video_path=None,
        **kwargs
    ):
    video_path = get_video_info_spec(
        video_url=video_url,
        video_path=video_path,
        download=True,
        key = 'video_path'
        )
    return video_path
def get_metadata_path(
        *args,
        video_url=None,
        video_path=None,
        **kwargs
    ):
    metadata_path = get_video_info_spec(
        video_url=video_url,
        video_path=video_path,
        download=True,
        key = 'metadata_path'
        )
    return metadata_path
def get_whisper_path(
        *args,
        video_url=None,
        video_path=None,
        **kwargs
    ):
    whisper_path = get_video_info_spec(
        video_url=video_url,
        video_path=video_path,
        download=True,
        key = 'whisper_path'
        )
    return whisper_path

logger = logging.getLogger(__name__)


def _safe_read_from_json(file_path, remove_if_corrupt=True, default=None):
    """
    Read JSON safely. If the file is corrupt, optionally remove it and return default.
    """
    if not file_path or not os.path.isfile(file_path):
        return default if default is not None else {}

    try:
        with open(file_path, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception as e:
        logger.error(f"Corrupt JSON detected at {file_path}: {e}")
        if remove_if_corrupt:
            try:
                os.remove(file_path)
                logger.warning(f"Removed corrupt JSON file: {file_path}")
            except Exception as rm_err:
                logger.error(f"Failed to remove corrupt JSON {file_path}: {rm_err}")
        return default if default is not None else {}


def _safe_dump_to_file(data, file_path=None, ensure_ascii=False, indent=4):
    """
    Dump JSON safely. If data is not JSON serializable, stringify it.
    """
    if not file_path:
        logger.error("safe_dump_to_file called without file_path")
        return

    if data is None:
        logger.warning(f"safe_dump_to_file got None for {file_path}, defaulting to empty dict")
        data = {}

    # Sanitize data for JSON
    try:
        with open(file_path, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=ensure_ascii, indent=indent)
    except (TypeError, ValueError) as e:
        logger.error(f"Non-serializable data for {file_path}: {e}, saving as string")
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(str(data))


def try_get_data(file_path):
    """
    Try to read JSON. If file is missing or corrupt, ensure it's replaced with {}.
    """
    if not file_path:
        return {}

    data = _safe_read_from_json(file_path)
    if not data:
        _safe_dump_to_file({}, file_path)
        return {}
    return data

def try_get_read(file_path):
    try:
        data = _safe_read_from_json(file_path)
        return data
    except:
        return False
    
def try_get_data(file_path):
    data = try_get_read(file_path)
    if not is_file(file_path) or not data:
        safe_dump_to_json(data={},file_path=file_path)
        return False
    return data
def get_whisper_audio_paths(video_url=None,video_path=None,force_refresh=False):
    if not video_path and not video_url or (video_path and not is_file(video_path) and not video_url):
        return
    if video_path and not video_url:
        video_id = generate_video_id(video_path)
    else:
        video_url = get_corrected_url(video_url)
        video_id = get_video_id(video_url)
    registry = infoRegistry()
    info = registry.get_video_info(
            url=video_url,
            video_id=video_id,
            video_path=video_path,
            force_refresh=force_refresh
            ) or {}
    video_info = info.get('info')
    if video_url and (not video_path or (video_path and not is_file(video_path))):
        video_mgr = VideoDownloader(
            url=video_url,
            download_video=True
            )

    if (video_path and is_file(video_path)) and is_media_type(video_path, categories=['video']):
        return self.video_info.get('audio_path')
def get_whisper_result(
        *args,
        audio_path=None,
        video_url=None,
        video_path=None,
        **kwargs
        ):
    whisper_path = get_whisper_path(
        video_url=video_url,
        video_path=video_path
        )
    data = try_get_data(whisper_path)
    if not data:
        audio_path = get_whisper_audio_path(
            audio_path=audio_path,
            video_url=video_url,
            video_path=video_path
            )        
        whisper_result = run_whisper_func(
                whisper_transcribe,
                *args,
                audio_path=audio_path,
                **kwargs
                )
        
        safe_dump_to_file(
            data=whisper_result,
            file_path=whisper_path
            )
    return try_get_data(whisper_path)
def get_whisper_text(
        *args,
        audio_path=None,
        video_url=None,
        video_path=None,
        **kwargs
        ):
    whisper_result = get_whisper_result(
            *args,
            audio_path=audio_path,
            video_url=video_url,
            video_path=video_path,
            **kwargs
            )
    return whisper_result.get('text')
def get_whisper_segments(
        *args,
        audio_path=None,
        video_url=None,
        video_path=None,
        **kwargs
        ):
    whisper_result = get_whisper_result(
            *args,
            audio_path=audio_path,
            video_url=video_url,
            video_path=video_path,
            **kwargs
            )
    return whisper_result.get('segments')
