"""
==================================================
Smart Attendance AI
Image Service
==================================================
Handles:
- Image validation
- File size validation
- Image decoding
- RGB → BGR conversion
- Returns ImageData object
==================================================
"""

import io

import cv2
import numpy as np

from PIL import Image
from fastapi import UploadFile

from typing import List

from config.constants import ALLOWED_IMAGE_TYPES

ALLOWED_TYPES = ALLOWED_IMAGE_TYPES

from config.logger import logger
from core.image_data import ImageData
from utils.exceptions import (
    InvalidImageException,
    UnsupportedImageFormatException,
    ImageTooLargeException
)


class ImageService:

    # ==========================================
    # Allowed MIME Types
    # ==========================================

    ALLOWED_TYPES = {

        "image/jpeg",

        "image/jpg",

        "image/png"

    }

    # ==========================================
    # Maximum Upload Size
    # ==========================================

    MAX_SIZE = 5 * 1024 * 1024      # 5 MB

    # ==========================================
    # Validate Image
    # ==========================================

    @classmethod
    async def validate(
        cls,
        file: UploadFile
    ):

        if file.content_type not in cls.ALLOWED_TYPES:

            logger.warning(
                "Unsupported image type: %s",
                file.content_type
            )

            raise UnsupportedImageFormatException()

        image_bytes = await file.read()

        size = len(image_bytes)

        if size > cls.MAX_SIZE:

            logger.warning(
                "Image too large: %.2f MB",
                size / (1024 * 1024)
            )

            raise ImageTooLargeException()

        await file.seek(0)

        return image_bytes

        # ==========================================
    # Read Multiple Images
    # ==========================================

    @classmethod
    async def read_multiple(
        cls,
        files: List[UploadFile]
    ) -> List[ImageData]:
        """
        Read multiple uploaded images.
        """

        images = []

        for file in files:

            image = await cls.read(
                file
            )

            images.append(
                image
            )

        return images

    # ==========================================
    # Read Image
    # ==========================================

    @classmethod
    async def read(
        cls,
        file: UploadFile
    ) -> ImageData:

        image_bytes = await cls.validate(file)

        try:

            pil_image = Image.open(
                io.BytesIO(image_bytes)
            ).convert("RGB")

        except Exception as ex:

            logger.exception(ex)

            raise InvalidImageException()

        image = np.array(pil_image)

        image = cv2.cvtColor(
            image,
            cv2.COLOR_RGB2BGR
        )

        height, width = image.shape[:2]

        channels = 1

        if len(image.shape) == 3:

            channels = image.shape[2]

        logger.info(

            "Image loaded (%s) [%dx%d]",

            file.filename,

            width,

            height

        )

        return ImageData(

            image=image,

            filename=file.filename or "unknown",

            content_type=file.content_type,

            file_size=len(image_bytes),

            width=width,

            height=height,

            channels=channels,

            color_mode="BGR"

        )


