from .imports import *
VIDEO_VARIABLE_KEYMAP = {
    "info": {
        "keys": ["info", "video_info", "video"],
        "type": dict,
    },
    "video_id": {
        "keys": ["id", "video_id"],
        "type": str or int,
    },
    "video_url": {
        "keys": ["url", "video_url"],
        "type": str,
    },
    "video_path": {
        "keys": ["path", "video_path"],
        "type": str,
    },
    "video_dir": {
        "keys": ["dir", "video_dir",'directory'],
        "type": str,
    },
}
def get_any_values(obj,values=None):
    values= make_list(values or [])
    for key in values:
        parts = [part for part in make_list(get_any_value(obj,'video_id') or [])]
        if parts and parts[0]:
            return parts[0]
def _build_reverse_keymap(keymap):
    reverse = {}
    for canonical_key, cfg in keymap.items():
        for alias in cfg["keys"]:
            reverse[alias] = canonical_key
    return reverse



VIDEO_KEYS = ("video_url", "video_id", "video_path", "info","video_dir")


def _is_url(value: str) -> bool:
    try:
        parsed = urlparse(value)
        return bool(parsed.scheme and parsed.netloc)
    except Exception:
        return False


def _is_path(value: str) -> bool:
    return (
        os.path.exists(value)
        or value.startswith(("/", "./", "../", "~"))
    )


def infer_video_arg(arg):
    """
    Infer (key, value) from a single positional argument.
    """
    if isinstance(arg, int):
        arg = str(arg)
    if isinstance(arg, dict):
        return "info", arg

    if isinstance(arg, Path):
        return "video_path", str(arg)

    if isinstance(arg, str or int):

        if _is_path(arg):
            if len(os.path.splitext(arg)) >1:        
                return "video_path", os.path.expanduser(arg)
            else:
                return "video_dir", os.path.expanduser(arg)
        if _is_url(arg):
            return "video_url", arg

        return "video_id", arg

    raise TypeError(f"Unsupported argument type: {type(arg).__name__}")
REVERSE_VIDEO_KEYMAP = _build_reverse_keymap(VIDEO_VARIABLE_KEYMAP)
def normalize_video_inputs(*args, **kwargs):
    """
    Normalizes positional args and keyword args into canonical video inputs.
    """

    normalized = {key: None for key in VIDEO_VARIABLE_KEYMAP}

    # 1️⃣ Positional args inference
    for arg in args:
        if isinstance(arg, int):
            arg = str(arg)
        key, value = infer_video_arg(arg)
        normalized[key] = value

    # 2️⃣ Keyword args override inference
    for incoming_key, value in kwargs.items():
        if isinstance(value, int):
            value = str(value)
        canonical_key = REVERSE_VIDEO_KEYMAP.get(incoming_key)
        if not canonical_key:
            continue

        expected_type = VIDEO_VARIABLE_KEYMAP[canonical_key]["type"]
        if value is not None and not isinstance(value, expected_type):
            raise TypeError(
                f"{canonical_key} must be {expected_type.__name__}, "
                f"got {type(value).__name__}"
            )

        # --- semantic validation for string values ---
        if isinstance(value, str):

            if canonical_key == "video_url" and not _is_url(value):
                # Demote to video_id
                normalized["video_id"] = value
                continue

            if canonical_key == "video_path" and not _is_path(value):
                # Demote to video_id
                normalized["video_id"] = value
                continue

        normalized[canonical_key] = value

    return normalized
def is_not_value(value):
    return value in [None,"",{},'',[]]
def update_data_value(data,key,value=None):
    data_value = data.get(key)
    if is_not_value(data_value):
        data[key] = value
    return data
def update_null_vars(data,update_data=None):
    update_data = update_data or {}
    for key,value in update_data.items():
        data = update_data_value(data,key,value)
    return data
def get_video_url_path_from_args(*args, **kwargs):
    data = normalize_video_inputs(*args, **kwargs)
    video_url = data["video_url"]
    video_id = data["video_id"]
    video_path = data["video_path"]
    info = data["info"]
    video_dir = data["video_dir"]
    if not video_id:
        if video_url:
            video_id = get_video_id(video_url)
        elif video_path:
            if video_path.startswith(VIDEOS_ROOT_DEFAULT):
                parts = [part for part in video_path.split(VIDEOS_ROOT_DEFAULT)[1].split('/') if part]
                if parts:
                    video_id = parts[0]
            else:
                video_id = generate_video_id(video_path)
        elif info:
            video_id = get_any_values(info,values=['video_id','id'])

        data['video_id']=video_id
    if not video_path:
        if info:
            video_path = get_any_values(info,values=['video_path','path'])
        elif video_id:
            video_path = os.path.join(VIDEOS_ROOT_DEFAULT,str(video_id),'video.mp4')
        data['video_path']=video_path
    if not video_dir:
        if video_path:
            video_dir = os.path.dirname(video_path)
        elif video_id:
            video_dir = os.path.join(VIDEOS_ROOT_DEFAULT,str(video_id))
        elif info:
            video_dir = get_any_values(info,values=['directory','video_directory'])
        data['video_dir']=video_dir
    if not video_url:
        if info:
            logger.info(f"info === {info}")
            video_url = get_any_values(info,values=['video_url','original_url'])
        data['video_url']=video_url
    if video_dir:
        if not os.path.isdir(video_dir):
            os.makedirs(video_dir,exist_ok=True)
        args_path = os.path.join(video_dir,'video_args.json')
        if not os.path.isfile(args_path):
            safe_dump_to_file(data={},file_path=args_path)
        args_info = safe_read_from_json(args_path)
        data = update_null_vars(args_info,update_data=data)
        safe_dump_to_file(data=data,file_path=args_path)
    return (
        data["video_url"],
        data["video_id"],
        data["video_path"],
        data["info"],
        data['video_dir'],
    )
