# app/modules/messaging/services/message_attachment_service.py
"""
Attachment handling service for messaging system.

Handles file upload, validation, storage, and retrieval.
"""

import logging
import os
import uuid
from datetime import datetime
from pathlib import Path

from fastapi import UploadFile
from sqlalchemy.orm import Session

from app.modules.core.services.admin_settings_service import admin_settings_service

logger = logging.getLogger(__name__)

# Allowed MIME types for attachments
ALLOWED_MIME_TYPES = {
    # Images
    "image/jpeg",
    "image/png",
    "image/gif",
    "image/webp",
    # Documents
    "application/pdf",
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    "application/vnd.ms-excel",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    # Archives
    "application/zip",
    # Text
    "text/plain",
    "text/csv",
}

IMAGE_MIME_TYPES = {"image/jpeg", "image/png", "image/gif", "image/webp"}

# Default max file size in MB
DEFAULT_MAX_FILE_SIZE_MB = 10


class MessageAttachmentService:
    """Service for handling message attachments."""

    def __init__(self, storage_base: str = "uploads/messages"):
        self.storage_base = storage_base

    def get_max_file_size_bytes(self, db: Session) -> int:
        """Get maximum file size from platform settings."""
        max_mb = admin_settings_service.get_setting_value(
            db,
            "message_attachment_max_size_mb",
            default=DEFAULT_MAX_FILE_SIZE_MB,
        )
        try:
            max_mb = int(max_mb)
        except (TypeError, ValueError):
            max_mb = DEFAULT_MAX_FILE_SIZE_MB
        return max_mb * 1024 * 1024  # Convert to bytes

    def validate_file_type(self, mime_type: str) -> bool:
        """Check if file type is allowed."""
        return mime_type in ALLOWED_MIME_TYPES

    def is_image(self, mime_type: str) -> bool:
        """Check if file is an image."""
        return mime_type in IMAGE_MIME_TYPES

    async def validate_and_store(
        self,
        db: Session,
        file: UploadFile,
        conversation_id: int,
    ) -> dict:
        """
        Validate and store an uploaded file.

        Returns dict with file metadata for MessageAttachment creation.

        Raises:
            ValueError: If file type or size is invalid
        """
        # Validate MIME type
        content_type = file.content_type or "application/octet-stream"
        if not self.validate_file_type(content_type):
            raise ValueError(
                f"File type '{content_type}' not allowed. "
                "Allowed types: images (JPEG, PNG, GIF, WebP), "
                "PDF, Office documents, ZIP, text files."
            )

        # Read file content
        content = await file.read()
        file_size = len(content)

        # Validate file size
        max_size = self.get_max_file_size_bytes(db)
        if file_size > max_size:
            raise ValueError(
                f"File size {file_size / 1024 / 1024:.1f}MB exceeds "
                f"maximum allowed size of {max_size / 1024 / 1024:.1f}MB"
            )

        # Generate unique filename
        original_filename = file.filename or "attachment"
        ext = Path(original_filename).suffix.lower()
        unique_filename = f"{uuid.uuid4().hex}{ext}"

        # Create storage path: uploads/messages/YYYY/MM/conversation_id/filename
        now = datetime.utcnow()
        relative_path = os.path.join(
            self.storage_base,
            str(now.year),
            f"{now.month:02d}",
            str(conversation_id),
        )

        # Ensure directory exists
        os.makedirs(relative_path, exist_ok=True)

        # Full file path
        file_path = os.path.join(relative_path, unique_filename)

        # Write file
        with open(file_path, "wb") as f:
            f.write(content)

        # Prepare metadata
        is_image = self.is_image(content_type)
        metadata = {
            "filename": unique_filename,
            "original_filename": original_filename,
            "file_path": file_path,
            "file_size": file_size,
            "mime_type": content_type,
            "is_image": is_image,
        }

        # Generate thumbnail for images
        if is_image:
            thumbnail_data = self._create_thumbnail(content, file_path)
            metadata.update(thumbnail_data)

        logger.info(
            f"Stored attachment {unique_filename} for conversation {conversation_id} "
            f"({file_size} bytes, type: {content_type})"
        )

        return metadata

    def _create_thumbnail(self, content: bytes, original_path: str) -> dict:
        """Create thumbnail for image attachments."""
        try:
            import io

            from PIL import Image

            img = Image.open(io.BytesIO(content))
            width, height = img.size

            # Create thumbnail
            img.thumbnail((200, 200))

            thumb_path = original_path.replace(".", "_thumb.")
            img.save(thumb_path)

            return {
                "image_width": width,
                "image_height": height,
                "thumbnail_path": thumb_path,
            }
        except ImportError:
            logger.warning("PIL not installed, skipping thumbnail generation")
            return {}
        except OSError as e:
            logger.error(f"Failed to create thumbnail: {e}")
            return {}

    def delete_attachment(
        self, file_path: str, thumbnail_path: str | None = None
    ) -> bool:
        """Delete attachment files from storage."""
        try:
            if os.path.exists(file_path):
                os.remove(file_path)
                logger.info(f"Deleted attachment file: {file_path}")

            if thumbnail_path and os.path.exists(thumbnail_path):
                os.remove(thumbnail_path)
                logger.info(f"Deleted thumbnail: {thumbnail_path}")

            return True
        except OSError as e:
            logger.error(f"Failed to delete attachment {file_path}: {e}")
            return False

    def get_download_url(self, file_path: str) -> str:
        """
        Get download URL for an attachment.

        For local storage, returns a relative path that can be served
        by the static file handler or a dedicated download endpoint.
        """
        # Convert local path to URL path
        # Files are served via the /uploads mount in main.py
        return f"/{file_path}"

    def get_file_content(self, file_path: str) -> bytes | None:
        """Read file content from storage."""
        try:
            if os.path.exists(file_path):
                with open(file_path, "rb") as f:
                    return f.read()
            return None
        except OSError as e:
            logger.error(f"Failed to read file {file_path}: {e}")
            return None


# Singleton instance
message_attachment_service = MessageAttachmentService()
