"""Image service for uploading, serving, and managing property images."""
import os
import uuid
from werkzeug.utils import secure_filename
from flask import current_app, url_for


# Allowed image extensions
ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'webp'}
MAX_PHOTOS_PER_PROPERTY = 20  # Maximum photos per property
MIN_WIDTH = 800
MIN_HEIGHT = 600


def allowed_file(filename):
    """Check if file extension is allowed."""
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


def validate_image(file):
    """
    Validate image file.
    
    Args:
        file: FileStorage object from request.files
        
    Returns:
        tuple: (is_valid, error_message)
    """
    if not file:
        return False, "No file provided"
    
    if file.filename == '':
        return False, "No file selected"
    
    if not allowed_file(file.filename):
        return False, f"Invalid file type. Allowed: {', '.join(ALLOWED_EXTENSIONS)}"
    
    try:
        file.seek(0, os.SEEK_SET)
        file.seek(0, os.SEEK_END)
        file_size = file.tell()
        file.seek(0, os.SEEK_SET)
        
    except Exception as e:
        current_app.logger.error(f"Error checking file size: {str(e)}")
        return False, "Error reading file"
    
    if file_size == 0:
        return False, "File is empty"
    
    return True, None


def generate_filename(original_filename, property_id, index=0):
    """
    Generate unique filename for uploaded image.
    
    Args:
        original_filename: Original file name
        property_id: UUID of property (house or car)
        index: Image index/order
        
    Returns:
        str: Unique filename
    """
    ext = original_filename.rsplit('.', 1)[1].lower()
    unique_id = uuid.uuid4().hex[:8]
    return f"{property_id}_{index}_{unique_id}.{ext}"


def get_upload_folder(folder_type):
    """
    Get upload folder path for specific type.
    
    Args:
        folder_type: 'houses' or 'cars'
        
    Returns:
        str: Full path to upload folder
    """
    base_dir = current_app.config.get('UPLOAD_FOLDER', 'static/uploads')
    folder_path = os.path.join(base_dir, folder_type)
    
    if not os.path.exists(folder_path):
        os.makedirs(folder_path, exist_ok=True)
    
    return folder_path


def upload_image(file, folder_type, property_id, index=0):
    """
    Upload a single image.
    
    Args:
        file: FileStorage object
        folder_type: 'houses' or 'cars'
        property_id: UUID of property
        index: Image index/order
        
    Returns:
        dict: {'success': bool, 'image_url': str/None, 'file_path': str/None, 'message': str}
    """
    is_valid, error = validate_image(file)
    if not is_valid:
        return {'success': False, 'image_url': None, 'file_path': None, 'message': error}
    
    try:
        filename = generate_filename(file.filename, property_id, index)
        upload_folder = get_upload_folder(folder_type)
        file_path = os.path.join(upload_folder, filename)
        
        file.save(file_path)
        
        image_url = filename
        
        return {
            'success': True,
            'image_url': image_url,
            'file_path': file_path,
            'message': 'Image uploaded successfully'
        }
        
    except Exception as e:
        current_app.logger.error(f"Image upload error: {str(e)}")
        return {
            'success': False,
            'image_url': None,
            'file_path': None,
            'message': f'Upload failed: {str(e)}'
        }


def should_rollback_error(error_message):
    """
    Determine if error should trigger rollback of all uploads.
    
    Args:
        error_message: Error message string
        
    Returns:
        bool: True if should rollback
    """
    critical_errors = [
        'disk space',
        'permission denied',
        'quota exceeded',
        'filesystem error'
    ]
    return any(err in error_message.lower() for err in critical_errors)


def upload_multiple_images(files, folder_type, property_id):
    """
    Upload multiple images with improved error handling and rollback.
    
    Args:
        files: List of FileStorage objects
        folder_type: 'houses' or 'cars'
        property_id: UUID of property
        
    Returns:
        dict: {'success': bool, 'images': list, 'errors': list, 'message': str}
    """
    # Validate photo count upfront
    if len(files) > MAX_PHOTOS_PER_PROPERTY:
        return {
            'success': False,
            'images': [],
            'errors': [{'error': f'Maximum {MAX_PHOTOS_PER_PROPERTY} photos allowed per property'}],
            'message': f'Too many photos. Maximum allowed: {MAX_PHOTOS_PER_PROPERTY}'
        }
    
    uploaded_images = []
    errors = []
    uploaded_paths = []  # Track file paths for potential rollback
    
    try:
        for index, file in enumerate(files):
            current_app.logger.info(f"Uploading image {index + 1}/{len(files)}: {file.filename}")
            
            result = upload_image(file, folder_type, property_id, index)
            
            if result['success']:
                uploaded_images.append({
                    'image_url': result['image_url'],
                    'display_order': index
                })
                uploaded_paths.append(result['image_url'])
                current_app.logger.info(f"Successfully uploaded: {result['image_url']}")
            else:
                error_info = {
                    'filename': file.filename,
                    'error': result['message'],
                    'index': index
                }
                errors.append(error_info)
                current_app.logger.warning(f"Failed to upload {file.filename}: {result['message']}")
                
                # Check if this is a critical error that should rollback everything
                if should_rollback_error(result['message']):
                    current_app.logger.error(f"Critical error detected, rolling back {len(uploaded_paths)} uploads")
                    for path in uploaded_paths:
                        delete_image(f"/static/uploads/{folder_type}/{path}")
                    return {
                        'success': False,
                        'images': [],
                        'errors': errors,
                        'message': f'Critical error: {result["message"]}. All uploads rolled back.'
                    }
        
        # Require at least one successful upload
        if len(uploaded_images) == 0:
            return {
                'success': False,
                'images': [],
                'errors': errors,
                'message': 'All image uploads failed'
            }
        
        success_message = f'Uploaded {len(uploaded_images)} of {len(files)} images'
        if errors:
            success_message += f' ({len(errors)} failed)'
        
        current_app.logger.info(success_message)
        
        return {
            'success': True,
            'images': uploaded_images,
            'errors': errors,
            'message': success_message
        }
        
    except Exception as e:
        # Unexpected exception - rollback all uploads
        current_app.logger.error(f"Unexpected error during upload: {str(e)}")
        for path in uploaded_paths:
            try:
                delete_image(f"/static/uploads/{folder_type}/{path}")
            except Exception as cleanup_error:
                current_app.logger.error(f"Failed to cleanup {path}: {str(cleanup_error)}")
        
        return {
            'success': False,
            'images': [],
            'errors': [{'error': f'Upload failed: {str(e)}'}],
            'message': 'Upload failed due to unexpected error. All uploads rolled back.'
        }


def get_image_url(filename, folder_type):
    """
    Generate URL for serving image.
    
    Args:
        filename: Image filename
        folder_type: 'houses' or 'cars'
        
    Returns:
        str: Full URL to image
    """
    return f"/static/uploads/{folder_type}/{filename}"


def delete_image(image_url):
    """
    Delete image from storage.
    
    Args:
        image_url: URL or path to image
        
    Returns:
        dict: {'success': bool, 'message': str}
    """
    try:
        if '/static/uploads/' in image_url:
            parts = image_url.split('/static/uploads/')
            if len(parts) == 2:
                relative_path = parts[1]
                base_dir = current_app.config.get('UPLOAD_FOLDER', 'static/uploads')
                file_path = os.path.join(base_dir, relative_path)
                
                if os.path.exists(file_path):
                    os.remove(file_path)
                    return {'success': True, 'message': 'Image deleted successfully'}
                else:
                    return {'success': False, 'message': 'Image file not found'}
        
        return {'success': False, 'message': 'Invalid image URL'}
        
    except Exception as e:
        current_app.logger.error(f"Image deletion error: {str(e)}")
        return {'success': False, 'message': f'Deletion failed: {str(e)}'}


def delete_multiple_images(image_urls):
    """
    Delete multiple images.
    
    Args:
        image_urls: List of image URLs
        
    Returns:
        dict: {'success': bool, 'deleted': int, 'failed': int}
    """
    deleted = 0
    failed = 0
    
    for url in image_urls:
        result = delete_image(url)
        if result['success']:
            deleted += 1
        else:
            failed += 1
    
    return {
        'success': deleted > 0,
        'deleted': deleted,
        'failed': failed,
        'message': f'Deleted {deleted} images, {failed} failed'
    }


def cleanup_orphaned_files():
    """
    Background job to clean up orphaned files.
    Files that exist on disk but have no corresponding database records.
    
    This should be run as a scheduled job (e.g., daily cron job).
    
    Returns:
        dict: {'success': bool, 'deleted': int, 'message': str}
    """
    from datetime import datetime, timedelta
    from app.models import HouseImage, CarImage
    
    try:
        max_age_hours = current_app.config.get('ORPHANED_FILE_MAX_AGE_HOURS', 24)
        cutoff_time = datetime.utcnow() - timedelta(hours=max_age_hours)
        
        deleted_count = 0
        
        # Check houses folder
        houses_folder = get_upload_folder('houses')
        for filename in os.listdir(houses_folder):
            file_path = os.path.join(houses_folder, filename)
            
            # Check file age
            file_modified = datetime.fromtimestamp(os.path.getmtime(file_path))
            if file_modified > cutoff_time:
                continue  # Skip recent files
            
            # Check if file has database record
            has_record = HouseImage.query.filter_by(image_url=filename).first() is not None
            
            if not has_record:
                os.remove(file_path)
                deleted_count += 1
                current_app.logger.info(f"Deleted orphaned house image: {filename}")
        
        # Check cars folder
        cars_folder = get_upload_folder('cars')
        for filename in os.listdir(cars_folder):
            file_path = os.path.join(cars_folder, filename)
            
            # Check file age
            file_modified = datetime.fromtimestamp(os.path.getmtime(file_path))
            if file_modified > cutoff_time:
                continue  # Skip recent files
            
            # Check if file has database record
            has_record = CarImage.query.filter_by(image_url=filename).first() is not None
            
            if not has_record:
                os.remove(file_path)
                deleted_count += 1
                current_app.logger.info(f"Deleted orphaned car image: {filename}")
        
        return {
            'success': True,
            'deleted': deleted_count,
            'message': f'Cleaned up {deleted_count} orphaned files'
        }
        
    except Exception as e:
        current_app.logger.error(f"Orphaned file cleanup error: {str(e)}")
        return {
            'success': False,
            'deleted': 0,
            'message': f'Cleanup failed: {str(e)}'
        }