from django.shortcuts import render, redirect
from django.contrib import messages
from django.db import transaction
from rest_framework import viewsets
from rest_framework.decorators import action

from .base import DummySerializer
import json



class StorageViewSet(viewsets.ModelViewSet):
    """Handles connecting and displaying cloud storage accounts (Google Drive, Dropbox, OneDrive)"""
    serializer_class = DummySerializer
    
    
    #### THIS HANDLES THE STORAGE SELECTION WITH SMART RECOMMENDATIONS ##########
    @action(detail=False, methods=['get', 'post'], url_path=r'')
    def storage_selection(self, request):
        """Step 3: Storage Selection with Smart Recommendations"""
        base_domain = request.build_absolute_uri('/')
        user = request.user
        
        if not user.is_authenticated:
            return redirect(f'{base_domain}login/')
        
        current_order_id = request.session.get('current_order_id')
        if not current_order_id:
            messages.error(request, "Please select files first")
            return redirect(f'{base_domain}transfer/new/')
        
        try:
            from ..models import TransferOrder
            # Use select_for_update to lock the row for update in case of concurrent requests
            order = TransferOrder.objects.select_for_update().get(id=current_order_id, user=user)
            
            # Calculate minimum required size (total + 1GB buffer)
            required_gb = float(order.total_size)
            minimum_required_gb = required_gb + 1.0  # Add 1GB buffer
            
            
            context = {
                'base_domain': base_domain,
                'user': user,
                'order': order,
                'current_step': 3,
                'selected_files_count': order.total_files,
                'total_size_gb': required_gb,
                'minimum_required_gb': minimum_required_gb,
                'kenyan_counties': self._get_kenyan_counties()
            }
            
            if request.method == 'POST':
                return self._handle_storage_selection(request, order, context)
            
            storage_data = self._get_all_storage_options(minimum_required_gb)
            
            # GET request - show storage options with smart recommendations
            context.update({
                'storage_options': self._get_storage_options(minimum_required_gb),
                'size_options': self._get_size_options(minimum_required_gb),
                'storage_devices': storage_data['devices'],
                'storage_capacities': storage_data['capacities'],
                'price_matrix_json': json.dumps(storage_data['price_matrix']),
            })
            
            return render(request, 'storage_selection.html', context)
            
        except TransferOrder.DoesNotExist:
            messages.error(request, "Order not found")
            return redirect(f'{base_domain}transfer/new/')

    
    def _handle_storage_selection(self, request, order, context):
        """Handle storage selection form submission with Kenyan address - FIXED VERSION"""
        print("=== STORAGE SELECTION HANDLER STARTED ===")
        
        base_domain = request.build_absolute_uri('/')
        storage_type = request.POST.get('storage_type')
        storage_size = request.POST.get('storage_size')
        
        print(f"DEBUG: storage_type = {storage_type}")
        print(f"DEBUG: storage_size = {storage_size}")
        
        # Kenyan address fields
        country = request.POST.get('country', 'Kenya')
        county = request.POST.get('county')
        district = request.POST.get('district')
        street_address = request.POST.get('street_address')
        town = request.POST.get('town')
        postal_code = request.POST.get('postal_code')
        additional_instructions = request.POST.get('additional_instructions', '')
        phone_number = request.POST.get('phone')
        
        print(f"DEBUG: county = {county}, district = {district}, town = {town}")
        print(f"DEBUG: street_address = {street_address}")
        
        # Validate required fields
        required_fields = [storage_type, storage_size, county, district, street_address, town , phone_number]
        print(f"DEBUG: Required fields check: {required_fields}")
        print(f"DEBUG: All fields present? {all(required_fields)}")
        
        if not all(required_fields):
            print("ERROR: Missing required fields")
            messages.error(request, "Please fill all required fields")
            context.update({
                'storage_options': self._get_storage_options(context['minimum_required_gb']),
                'size_options': self._get_size_options(context['minimum_required_gb']),
                'kenyan_counties': self._get_kenyan_counties()
            })
            return render(request, 'storage_selection.html', context)
        
        print("DEBUG: All required fields present")
        
        # Validate storage size
        try:
            required_gb = context['minimum_required_gb']
            print(f"DEBUG: Minimum required GB from context: {required_gb}")
            
            # Parse storage size - handle both GB and TB
            storage_size_clean = storage_size.upper().strip()
            print(f"DEBUG: Clean storage size: {storage_size_clean}")
            
            if 'TB' in storage_size_clean:
                # Convert TB to GB (1TB = 1000GB)
                tb_value = float(storage_size_clean.replace('TB', '').strip())
                selected_gb = int(tb_value * 1000)
                storage_size_for_db = storage_size_clean
                print(f"DEBUG: Converted {tb_value}TB to {selected_gb}GB")
            elif 'GB' in storage_size_clean:
                # Already in GB
                selected_gb = int(storage_size_clean.replace('GB', '').strip())
                storage_size_for_db = storage_size_clean
                print(f"DEBUG: Parsed {selected_gb}GB directly")
            else:
                # Assume it's in GB if no unit specified
                selected_gb = int(storage_size_clean)
                storage_size_for_db = f"{selected_gb}GB"
                print(f"DEBUG: No unit specified, assuming GB: {selected_gb}GB")
            
            print(f"DEBUG: Selected GB after parsing: {selected_gb}")
            print(f"DEBUG: Storage size for DB: {storage_size_for_db}")
            
            if selected_gb < required_gb:
                print(f"ERROR: Selected GB ({selected_gb}) < Required GB ({required_gb})")
                messages.error(request, f"Selected storage ({storage_size}) is too small. Minimum {required_gb:.1f} GB required")
                context.update({
                    'storage_options': self._get_storage_options(required_gb),
                    'size_options': self._get_size_options(required_gb),
                    'kenyan_counties': self._get_kenyan_counties()
                })
                return render(request, 'storage_selection.html', context)
            
            print("DEBUG: Storage size validation passed")
            
            # Build complete shipping address
            shipping_parts = [
                street_address,
                town,
                district,
                county,
                f"Postal Code: {postal_code}" if postal_code else None,
                country,
                f"Phone: {phone_number}" if phone_number else None
            ]
            shipping_address = ", ".join([part for part in shipping_parts if part])
            
            if additional_instructions:
                shipping_address += f"\n\nAdditional Instructions: {additional_instructions}"
            
            print(f"DEBUG: Shipping address built: {shipping_address[:150]}...")
            
            # UPDATE ORDER WITH TRANSACTION ATOMIC FOR DATA CONSISTENCY
            from django.db import transaction
            
            try:
                print("DEBUG: Starting transaction for order update")
                with transaction.atomic():
                    # Update order fields
                    order.storage_type = storage_type
                    order.storage_size = storage_size_for_db  # Use the properly formatted size
                    order.shipping_address = shipping_address
                    order.status = 'storage_selected'
                    
                    print(f"DEBUG: Order update - storage_type: {storage_type}")
                    print(f"DEBUG: Order update - storage_size: {storage_size_for_db}")
                    print(f"DEBUG: Order update - status: storage_selected")
                    
                    # Use update_fields for faster saving with only changed fields
                    order.save(update_fields=[
                        'storage_type', 
                        'storage_size', 
                        'shipping_address', 
                        'status',
                        'updated_at'  # if you have this field
                    ])
                    
                    print("DEBUG: Order saved successfully")
                    
                    # Verify the save worked
                    order.refresh_from_db()
                    print(f"DEBUG: Refreshed order status: {order.status}")
                    print(f"DEBUG: Refreshed order storage_size: {order.storage_size}")
                    
                    if order.status != 'storage_selected':
                        print("ERROR: Order status not updated correctly after save")
                        raise Exception("Order not updated correctly")
                    
                    print("DEBUG: Order verification passed")
                    print(f"DEBUG: Redirecting to: {base_domain}transfer/payment/")
                    
                    return redirect(f'{base_domain}transfer/payment/')
                    
            except Exception as e:
                print(f"ERROR IN TRANSACTION: {type(e).__name__}: {str(e)}")
                messages.error(request, "Failed to save your selection. Please try again.")
                # Log the error for debugging
                print(f"Full error saving order: {e}")
                import traceback
                print(f"Traceback: {traceback.format_exc()}")
                context.update({
                    'storage_options': self._get_storage_options(context['minimum_required_gb']),
                    'size_options': self._get_size_options(context['minimum_required_gb']),
                    'kenyan_counties': self._get_kenyan_counties()
                })
                return render(request, 'storage_selection.html', context)
                
        except (ValueError, AttributeError) as e:
            print(f"ERROR PARSING STORAGE SIZE: {type(e).__name__}: {str(e)}")
            messages.error(request, "Invalid storage size selected. Please enter a valid size like '1TB' or '500GB'")
            context.update({
                'storage_options': self._get_storage_options(context['minimum_required_gb']),
                'size_options': self._get_size_options(context['minimum_required_gb']),
                'kenyan_counties': self._get_kenyan_counties()
            })
            return render(request, 'storage_selection.html', context)
        
        finally:
            print("=== STORAGE SELECTION HANDLER ENDED ===")      

    def _get_storage_options(self, required_gb):
        """Get storage options with smart recommendations based on file size"""
        options = [
            {
                'type': 'flash_drive', 
                'name': 'USB Flash Drive', 
                'icon': 'usb', 
                'description': 'Portable and durable USB 3.0 drives',
                'max_capacity': 1024,  # GB
                'recommended': required_gb <= 256  # Best for smaller transfers
            },
            {
                'type': 'memory_card', 
                'name': 'Memory Card', 
                'icon': 'sd-card', 
                'description': 'Compact SD/microSD cards with adapter',
                'max_capacity': 512,   # GB
                'recommended': required_gb <= 128   # Best for photos/videos
            },
            {
                'type': 'external_hdd', 
                'name': 'External HDD', 
                'icon': 'hdd', 
                'description': 'Large capacity portable hard drives',
                'max_capacity': 5000,  # GB
                'recommended': required_gb > 256   # Best for large transfers
            }
        ]
        
        # Filter out options that can't handle the required size
        suitable_options = [opt for opt in options if opt['max_capacity'] >= required_gb]
        
        # If no suitable options, return the largest one
        if not suitable_options:
            suitable_options = [options[-1]]
        
        # Remove max_capacity from final output
        for opt in suitable_options:
            opt.pop('max_capacity', None)
        
        return suitable_options

    def _get_size_options(self, required_gb):
        """Get size options with smart recommendations"""
        base_sizes = [
            {'size': '64GB', 'gb': 64, 'price': 1200, 'suitable_for': 'Documents, Photos', 'popular': required_gb <= 50},
            {'size': '128GB', 'gb': 128, 'price': 2200, 'suitable_for': 'Photos, Music, Videos', 'popular': required_gb <= 100},
            {'size': '256GB', 'gb': 256, 'price': 3800, 'suitable_for': 'Large photo libraries, HD videos', 'popular': required_gb <= 200},
            {'size': '512GB', 'gb': 512, 'price': 6500, 'suitable_for': 'Video projects, backups', 'popular': required_gb <= 400},
            {'size': '1TB', 'gb': 1024, 'price': 9500, 'suitable_for': 'Large backups, media collections', 'popular': required_gb <= 800},
            {'size': '2TB', 'gb': 2048, 'price': 15000, 'suitable_for': 'Extensive media libraries', 'popular': required_gb <= 1800}
        ]
        
        # Filter sizes that can accommodate the files + buffer
        suitable_sizes = [size for size in base_sizes if size['gb'] >= required_gb]
        
        # If no suitable sizes, show the largest available
        if not suitable_sizes:
            suitable_sizes = [base_sizes[-1]]
        
        # Mark the smallest suitable size as recommended (cost-effective)
        if suitable_sizes:
            suitable_sizes[0]['recommended'] = True
        
        return suitable_sizes

    def _get_kenyan_counties(self):
        """Get complete list of all 47 Kenyan counties"""
        return [
            'Baringo', 'Bomet', 'Bungoma', 'Busia', 'Elgeyo Marakwet', 'Embu', 'Garissa',
            'Homa Bay', 'Isiolo', 'Kajiado', 'Kakamega', 'Kericho', 'Kiambu', 'Kilifi',
            'Kirinyaga', 'Kisii', 'Kisumu', 'Kitui', 'Kwale', 'Laikipia', 'Lamu',
            'Machakos', 'Makueni', 'Mandera', 'Marsabit', 'Meru', 'Migori', 'Mombasa',
            'Muranga', 'Nairobi', 'Nakuru', 'Nandi', 'Narok', 'Nyamira', 'Nyandarua',
            'Nyeri', 'Samburu', 'Siaya', 'Taita Taveta', 'Tana River', 'Tharaka Nithi',
            'Trans Nzoia', 'Turkana', 'Uasin Gishu', 'Vihiga', 'Wajir', 'West Pokot'
        ]
    
    
    
    def _get_device_types(self, required_gb):
        """
        Return all available device types with realistic capacity limits
        based on current market availability in Kenya.
        """
        return [
            {
                'type': 'usb',
                'name': 'USB Flash Drive',
                'icon': 'usb',
                'description': 'Portable, USB 3.0',
                'speed': 'High speed',
                'price_factor': 1.0,
                'max_capacity_gb': 256   # Physical limitation of small form factor
            },
            {
                'type': 'memory_card',
                'name': 'Memory Card',
                'icon': 'sd-card',
                'description': 'SD/microSD, Class 10',
                'speed': 'Versatile',
                'price_factor': 1.1,
                'max_capacity_gb': 1500  # 1.5TB SDXC cards exist in the market[reference:4]
            },
            {
                'type': 'ssd',
                'name': 'SSD',
                'icon': 'microchip',
                'description': 'Solid State Drive',
                'speed': 'Lightning fast',
                'price_factor': 2.8,
                'max_capacity_gb': 8000  # 8TB portable SSDs available[reference:5]
            },
            {
                'type': 'hdd',
                'name': 'HDD',
                'icon': 'database',
                'description': 'Hard Disk Drive',
                'speed': 'Best value',
                'price_factor': 1.5,
                'max_capacity_gb': 12000 # 12TB desktop external drives exist[reference:6]
            }
        ]
        

    def _get_capacity_price_list(self, required_gb, device_type=None):
        """
        Return list of capacities with base prices (per GB) for USB baseline.
        Prices are realistic for the Kenyan market as of 2026 (in KES).
        
        max_gb is passed dynamically from device's max_capacity_gb.
        """
        # Available capacities in GB - common market sizes
        all_capacities = [
            {'size': '64GB',   'gb': 64,   'base_price': 1200},
            {'size': '128GB',  'gb': 128,  'base_price': 2200},
            {'size': '256GB',  'gb': 256,  'base_price': 3800},
            {'size': '512GB',  'gb': 512,  'base_price': 6500},
            {'size': '1TB',    'gb': 1024, 'base_price': 9500},
            {'size': '2TB',    'gb': 2048, 'base_price': 15000},
            {'size': '4TB',    'gb': 4096, 'base_price': 28000},
            {'size': '5TB',    'gb': 5120, 'base_price': 35000},
            {'size': '8TB',    'gb': 8192, 'base_price': 52000},
            {'size': '12TB',   'gb': 12288, 'base_price': 78000}
        ]
        
        # If device_type is provided, filter capacities that fit within max capacity
        if device_type:
            devices = self._get_device_types(required_gb)
            max_capacity = next((d['max_capacity_gb'] for d in devices if d['type'] == device_type), 8192)
            suitable = [c for c in all_capacities if c['gb'] <= max_capacity and c['gb'] >= required_gb]
        else:
            suitable = [c for c in all_capacities if c['gb'] >= required_gb]
        
        # Always show at least 3 options, preferring larger ones if needed
        if len(suitable) < 3:
            # Add next larger capacities up to max
            for c in all_capacities:
                if c not in suitable and c['gb'] >= required_gb and (not device_type or c['gb'] <= max_capacity):
                    suitable.append(c)
                    if len(suitable) >= 5:
                        break
        
        return sorted(suitable, key=lambda x: x['gb'])


    def _get_all_storage_options(self, required_gb):
        """
        Combine device types and capacities with computed prices.
        Returns a dict with devices list and a price matrix.
        """
        devices = self._get_device_types(required_gb)
        price_matrix = {}
        
        for device in devices:
            device_type = device['type']
            # Get capacities specifically for this device's max capacity
            capacities = self._get_capacity_price_list(required_gb, device_type)
            price_matrix[device_type] = {}
            
            for cap in capacities:
                # Base price * device factor, rounded to nearest 50 KES
                raw_price = cap['base_price'] * device['price_factor']
                rounded_price = int(round(raw_price / 50) * 50)
                price_matrix[device_type][cap['size']] = rounded_price
            
            # Store capacities for this device in device dict for frontend use
            device['available_capacities'] = [c['size'] for c in capacities]
        
        # Collect all unique capacities across all devices for display
        all_capacities = []
        seen_sizes = set()
        for cap in self._get_capacity_price_list(required_gb):
            if cap['size'] not in seen_sizes:
                seen_sizes.add(cap['size'])
                all_capacities.append(cap)
        
        return {
            'devices': devices,
            'capacities': all_capacities,
            'price_matrix': price_matrix
        }