import os
import uuid
from pathlib import Path
from typing import Tuple
from uuid import UUID
from PIL import Image
from io import BytesIO
import aiofiles
from application.interfaces.file_storage import FileStoragePort

class LocalFileStorageService(FileStoragePort):
    """Local filesystem implementation of file storage"""
    
    def __init__(self, storage_root: str = "storage/uploads"):
        self.storage_root = Path(storage_root)
        self._ensure_storage_root()
    
    def _ensure_storage_root(self):
        """Create storage directory if it doesn't exist"""
        self.storage_root.mkdir(parents=True, exist_ok=True)
    
    def generate_file_path(self, user_id: UUID, extension: str) -> str:
        """Generate a unique file path in user-specific directory"""
        user_dir = self.storage_root / str(user_id)
        user_dir.mkdir(exist_ok=True)
        
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"{timestamp}_{uuid.uuid4().hex}.{extension}"
        return str(user_dir / filename)
    
    async def save_chart_image(
        self, 
        user_id: UUID, 
        image_data: bytes, 
        content_type: str
    ) -> str:
        """Save image data to filesystem"""
        # Determine file extension from content type
        extension = self._get_extension_from_content_type(content_type)
        file_path = self.generate_file_path(user_id, extension)
        
        async with aiofiles.open(file_path, "wb") as f:
            await f.write(image_data)
        
        return file_path
    
    async def get_chart_image(self, file_path: str) -> Tuple[bytes, str]:
        """Retrieve image data from filesystem"""
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")
        
        async with aiofiles.open(file_path, "rb") as f:
            content = await f.read()
        
        content_type = self._get_content_type_from_extension(file_path)
        return content, content_type
    
    async def generate_thumbnail(
        self, 
        original_path: str, 
        output_path: str,
        dimensions: Tuple[int, int] = (300, 300)
    ) -> str:
        """Generate thumbnail version of an image"""
        # Read original image
        content, _ = await self.get_chart_image(original_path)
        
        # Create thumbnail
        with Image.open(BytesIO(content)) as img:
            img.thumbnail(dimensions)
            
            # Determine format from original extension
            ext = Path(original_path).suffix[1:].lower()
            if ext in ['jpg', 'jpeg']:
                format = 'JPEG'
            elif ext == 'png':
                format = 'PNG'
            else:
                format = ext.upper()
            
            # Save thumbnail
            thumb_dir = Path(output_path).parent
            thumb_dir.mkdir(parents=True, exist_ok=True)
            
            img.save(output_path, format=format)
        
        return output_path
    
    async def delete_file(self, file_path: str) -> bool:
        """Delete a file from storage"""
        try:
            os.unlink(file_path)
            return True
        except OSError:
            return False
    
    def _get_extension_from_content_type(self, content_type: str) -> str:
        """Map content type to file extension"""
        mapping = {
            'image/png': 'png',
            'image/jpeg': 'jpg',
            'image/jpg': 'jpg',
            'image/webp': 'webp'
        }
        return mapping.get(content_type.lower(), 'bin')
    
    def _get_content_type_from_extension(self, file_path: str) -> str:
        """Map file extension to content type"""
        ext = Path(file_path).suffix[1:].lower()
        mapping = {
            'png': 'image/png',
            'jpg': 'image/jpeg',
            'jpeg': 'image/jpeg',
            'webp': 'image/webp'
        }
        return mapping.get(ext, 'application/octet-stream')