import cloudinary
import cloudinary.uploader
from fastapi import HTTPException, status, UploadFile
from typing import Optional
import os
from dotenv import load_dotenv

load_dotenv()

# Cloudinary configuration
CLOUD_NAME = os.getenv("CLOUDINARY_CLOUD_NAME", "dnwxrqvth")
API_KEY = os.getenv("CLOUDINARY_API_KEY", "658588413175913")
API_SECRET = os.getenv("CLOUDINARY_API_SECRET", "rSbOvPyQormfGojL1JiGlzyNX6Q")

# Validate Cloudinary configuration
if not CLOUD_NAME or not API_KEY or not API_SECRET:
    raise RuntimeError(
        "Cloudinary credentials not configured. Please set CLOUDINARY_CLOUD_NAME, "
        "CLOUDINARY_API_KEY, and CLOUDINARY_API_SECRET environment variables."
    )

# Configure Cloudinary
cloudinary.config(
    cloud_name=CLOUD_NAME,
    api_key=API_KEY,
    api_secret=API_SECRET
)

# Allowed image formats
ALLOWED_IMAGE_TYPES = {"image/jpeg", "image/jpg", "image/png", "image/webp", "image/gif"}
MAX_FILE_SIZE = 5 * 1024 * 1024  # 5MB in bytes


def validate_image_file(file: UploadFile) -> None:
    """Validate image file type and size"""
    if not file.content_type:
        # Try to detect from filename if content_type is missing
        filename = file.filename or ""
        if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.webp', '.gif')):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="File type could not be determined. Please ensure the file is an image (JPEG, PNG, WebP, GIF)"
            )
    elif file.content_type not in ALLOWED_IMAGE_TYPES:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid file type: {file.content_type}. Allowed types: JPEG, PNG, WebP, GIF"
        )
    
    # Read file to check size
    try:
        file.file.seek(0, 2)  # Seek to end
        file_size = file.file.tell()
        file.file.seek(0)  # Reset to beginning
        
        if file_size > MAX_FILE_SIZE:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"File size exceeds 5MB limit. Current size: {file_size / (1024 * 1024):.2f}MB"
            )
        if file_size == 0:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="File is empty"
            )
    except Exception as e:
        if isinstance(e, HTTPException):
            raise
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Error reading file: {str(e)}"
        )


def upload_image_to_cloudinary(
    file: UploadFile,
    folder: Optional[str] = None,
    public_id: Optional[str] = None
) -> str:
    """
    Upload an image file to Cloudinary
    
    Args:
        file: FastAPI UploadFile object
        folder: Optional folder path in Cloudinary
        public_id: Optional public ID for the image
    
    Returns:
        str: URL of the uploaded image
    """
    validate_image_file(file)
    
    try:
        # Read file content
        file.file.seek(0)
        file_content = file.file.read()
        file.file.seek(0)
        
        if not file_content:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="File is empty or could not be read"
            )
        
        # Upload options
        upload_options = {
            "resource_type": "image",
        }
        
        if folder:
            upload_options["folder"] = folder
        
        if public_id:
            upload_options["public_id"] = public_id
        
        # Upload to Cloudinary
        result = cloudinary.uploader.upload(
            file_content,
            **upload_options
        )
        
        if not result:
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Cloudinary upload returned no result"
            )
        
        image_url = result.get("secure_url") or result.get("url")
        if not image_url:
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Cloudinary upload succeeded but no URL was returned"
            )
        
        return image_url
    
    except HTTPException:
        raise
    except Exception as e:
        error_msg = str(e)
        # Provide more helpful error messages
        if "Invalid API Key" in error_msg or "401" in error_msg:
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Cloudinary authentication failed. Please check your API credentials."
            )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error uploading image to Cloudinary: {error_msg}"
        )


def delete_image_from_cloudinary(public_id: str) -> bool:
    """
    Delete an image from Cloudinary
    
    Args:
        public_id: Public ID of the image to delete
    
    Returns:
        bool: True if deletion was successful
    """
    try:
        result = cloudinary.uploader.destroy(public_id)
        return result.get("result") == "ok"
    except Exception:
        return False


def extract_public_id_from_url(url: str) -> Optional[str]:
    """
    Extract public_id from Cloudinary URL
    
    Args:
        url: Cloudinary image URL
    
    Returns:
        Optional[str]: Public ID if found, None otherwise
    """
    try:
        # Cloudinary URLs typically have format:
        # https://res.cloudinary.com/{cloud_name}/image/upload/{version}/{folder}/{public_id}.{format}
        # or
        # https://res.cloudinary.com/{cloud_name}/image/upload/{folder}/{public_id}.{format}
        if "cloudinary.com" not in url or "image/upload" not in url:
            return None
        
        parts = url.split("/")
        upload_index = parts.index("upload")
        if upload_index + 1 >= len(parts):
            return None
        
        # Get everything after 'upload'
        path_after_upload = "/".join(parts[upload_index + 1:])
        
        # Remove version if present (format: v1234567890/...)
        if path_after_upload.startswith("v") and "/" in path_after_upload:
            path_after_upload = "/".join(path_after_upload.split("/")[1:])
        
        # Remove file extension (last part after the last dot)
        if "." in path_after_upload:
            public_id = ".".join(path_after_upload.rsplit(".", 1)[:-1])
        else:
            public_id = path_after_upload
        
        return public_id if public_id else None
    except Exception:
        pass
    return None

