"""File handling utilities."""

import mimetypes
import os
import re
from pathlib import Path
from typing import BinaryIO, Union

from kamimind_storage.constants import DEFAULT_CONTENT_TYPE


def get_file_size(file: Union[str, Path, BinaryIO]) -> int:
    """Get the size of a file in bytes.

    Args:
        file: File path or file-like object.

    Returns:
        File size in bytes.
    """
    if isinstance(file, (str, Path)):
        return os.path.getsize(file)

    # File-like object
    current_pos = file.tell()
    file.seek(0, os.SEEK_END)
    size = file.tell()
    file.seek(current_pos)
    return size


def get_content_type(filename: str) -> str:
    """Detect content type from filename.

    Args:
        filename: Name of the file.

    Returns:
        MIME type string.
    """
    content_type, _ = mimetypes.guess_type(filename)
    return content_type or DEFAULT_CONTENT_TYPE


def sanitize_filename(filename: str) -> str:
    """Sanitize a filename for safe storage.

    Args:
        filename: Original filename.

    Returns:
        Sanitized filename.
    """
    # Remove path separators
    filename = filename.replace("/", "_").replace("\\", "_")

    # Remove path traversal
    filename = filename.replace("..", "_")

    # Remove null bytes
    filename = filename.replace("\x00", "")

    # Remove control characters
    filename = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", filename)

    # Limit length
    if len(filename) > 255:
        name, ext = os.path.splitext(filename)
        filename = name[: 255 - len(ext)] + ext

    return filename or "unnamed"


def calculate_total_parts(file_size: int, part_size: int) -> int:
    """Calculate the number of parts for multipart upload.

    Args:
        file_size: Total file size in bytes.
        part_size: Size of each part in bytes.

    Returns:
        Number of parts.
    """
    return (file_size + part_size - 1) // part_size
