"""Model Hub utility for downloading and caching models from Hugging Face.

This module provides utilities to download model files from Hugging Face Hub
and cache them locally for efficient reuse.

Note: This downloads from a public repository and does not require authentication
for end users.
"""

import os
from pathlib import Path
from typing import Optional

from huggingface_hub import hf_hub_download


def download_model(
    filename: str,
    subfolder: Optional[str] = None,
    repo_id: str = "ishandutta/mukh-models",
    cache_dir: Optional[str] = None,
    force_download: bool = False,
) -> str:
    """Download a model file from Hugging Face Hub.

    This downloads from a public repository and requires no authentication.

    Args:
        filename: Name of the file to download
        subfolder: Optional subfolder within the repository
        repo_id: Hugging Face repository ID for the models
        cache_dir: Optional custom cache directory. If None, uses default HF cache.
        force_download: Whether to force re-download even if cached

    Returns:
        Local path to the downloaded model file

    Raises:
        Exception: If download fails or file not found
    """
    try:
        # Check if file exists in cache first (unless force_download is True)
        if not force_download:
            try:
                # Try to get the file without downloading (will raise if not cached)
                file_path = hf_hub_download(
                    repo_id=repo_id,
                    filename=filename,
                    subfolder=subfolder,
                    cache_dir=cache_dir,
                    local_files_only=True,
                    token=False,
                )
                return file_path
            except Exception:
                # File not in cache, need to download
                print(
                    f"Downloading {filename} from Hugging Face Hub (no authentication required)..."
                )

        file_path = hf_hub_download(
            repo_id=repo_id,
            filename=filename,
            subfolder=subfolder,
            cache_dir=cache_dir,
            force_download=force_download,
            token=False,  # Explicitly disable token for public downloads
        )

        if not force_download:
            print(f"✅ {filename} downloaded successfully!")

        return file_path
    except Exception as e:
        error_msg = f"Failed to download {filename} from {repo_id}"
        if "401" in str(e) or "authentication" in str(e).lower():
            error_msg += "\n\nThis may indicate the repository is private or requires authentication."
            error_msg += (
                "\nPlease ensure the repository is public for end users to access."
            )
        elif "404" in str(e) or "not found" in str(e).lower():
            error_msg += "\n\nThe model file was not found in the repository."
            error_msg += f"\nPlease check if {filename} exists in {subfolder or 'root'} of {repo_id}"
        else:
            error_msg += f"\nError details: {str(e)}"

        raise Exception(error_msg)


def download_blazeface_models() -> tuple[str, str]:
    """Download BlazeFace model files.

    Downloads from public repository without requiring authentication.

    Returns:
        Tuple of (weights_path, anchors_path)

    Raises:
        Exception: If download fails
    """
    try:
        weights_path = download_model(
            "blazeface.pth", subfolder="face_detection/blazeface"
        )
        anchors_path = download_model(
            "anchors.npy", subfolder="face_detection/blazeface"
        )
        return weights_path, anchors_path
    except Exception as e:
        raise Exception(f"Failed to download BlazeFace models: {str(e)}")


def download_ultralight_model(model_variant: str = "RFB-320") -> tuple[str, str]:
    """Download UltraLight model files.

    Downloads from public repository without requiring authentication.

    Args:
        model_variant: Model variant to download ("RFB-320", "RFB-640", "slim-320", "slim-640")

    Returns:
        Tuple of (weights_path, labels_path)

    Raises:
        Exception: If download fails
    """
    try:
        weights_filename = f"version-{model_variant}.pth"
        weights_path = download_model(
            weights_filename, subfolder="face_detection/ultralight"
        )
        labels_path = download_model(
            "voc-model-labels.txt", subfolder="face_detection/ultralight"
        )
        return weights_path, labels_path
    except Exception as e:
        raise Exception(
            f"Failed to download UltraLight models for variant {model_variant}: {str(e)}"
        )


def download_reenactment_model(model_name: str = "vox") -> str:
    """Download reenactment model checkpoint.

    Downloads only the model checkpoint from public repository without requiring authentication.
    Config files remain bundled with the package.

    Args:
        model_name: Model name to download ("vox", "ted", "taichi")

    Returns:
        Local path to the downloaded model checkpoint

    Raises:
        Exception: If download fails
    """
    try:
        model_filename = f"{model_name}.pth.tar"
        model_path = download_model(
            model_filename, subfolder="face_reenactment/thin_plate_spline"
        )
        return model_path
    except Exception as e:
        raise Exception(
            f"Failed to download reenactment model for {model_name}: {str(e)}"
        )


def download_resnet_inception_model(
    model_path: str = "resnetinceptionv1_epoch_32.pth",
) -> str:
    """Download ResNet Inception model checkpoint.

    Downloads only the model checkpoint from public repository without requiring authentication.
    Config files remain bundled with the package.
    """
    try:
        model_path = download_model(
            model_path, subfolder="deepfake_detection/resnet_inception"
        )
        return model_path
    except Exception as e:
        raise Exception(f"Failed to download ResNet Inception model: {str(e)}")


def download_resnext_model(
    model_path: str = "model_97_acc_100_frames_FF_data.pt",
) -> str:
    """Download ResNeXt model checkpoint.

    Downloads only the model checkpoint from public repository without requiring authentication.
    Config files remain bundled with the package.
    """
    try:
        model_path = download_model(model_path, subfolder="deepfake_detection/resnext")
        return model_path
    except Exception as e:
        raise Exception(f"Failed to download ResNeXt model: {str(e)}")
