from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from django.core.validators import EmailValidator
from django.utils import timezone
import uuid

class Profile(models.Model):
    
    # UUID primary key for better scalability and security
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
        unique=True
    )
    
    # Link to Django's built-in User model
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        related_name='profile',
        verbose_name=_("User")
    )
    
    # Email field
    email = models.EmailField(
        _("Email Address"),
        max_length=255,
        unique=True,
        validators=[EmailValidator()],
        help_text=_("Primary email address for the account")
    )
    
    # Terms and conditions agreement
    agreed_to_terms = models.BooleanField(
        _("Agreed to Terms"),
        default=False,
        help_text=_("Whether the user agreed to terms and conditions")
    )
    
    # Date and time when the user agreed to terms
    terms_agreed_at = models.DateTimeField(
        _("Terms Agreed At"),
        null=True,
        blank=True,
        help_text=_("When the user agreed to the terms and conditions")
    )
    
    # Timestamps
    created_at = models.DateTimeField(
        _("Created At"),
        auto_now_add=True,
        help_text=_("When the profile was created")
    )
    
    updated_at = models.DateTimeField(
        _("Updated At"),
        auto_now=True,
        help_text=_("When the profile was last updated")
    )
    
    class Meta:
        verbose_name = _("Profile")
        verbose_name_plural = _("Profiles")
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['email']),
            models.Index(fields=['created_at']),
            models.Index(fields=['user', 'created_at']),
        ]
    
    def __str__(self):
        return f"{self.user.username} - {self.email}"
    
    def save(self, *args, **kwargs):
        # Auto-set terms_agreed_at when agreed_to_terms is True
        if self.agreed_to_terms and not self.terms_agreed_at:
            self.terms_agreed_at = timezone.now()
        
        # Ensure email is synchronized with User model
        if self.user and self.user.email != self.email:
            self.user.email = self.email
            self.user.save()
        
        super().save(*args, **kwargs)
    
    @property
    def username(self):
        """Convenience method to get username from User model"""
        return self.user.username
    
# Local file uploads model from clients machine
class LocalUploadedFile(models.Model):
    
    """Store files uploaded from user's local computer"""
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False
    )
    
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='local_uploads')
    transfer_order = models.ForeignKey(
        'TransferOrder',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='local_files'
    )
    
    # File information
    original_name = models.CharField(max_length=500)
    file_size = models.BigIntegerField()  # In bytes
    file = models.FileField(upload_to='local_uploads/%Y/%m/%d/')
    
    # Tracking
    uploaded_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-uploaded_at']
    
    def __str__(self):
        return f"{self.original_name} ({self.user.email})"
    
    @property
    def file_url(self):
        """URL for admin to download this file"""
        return self.file.url if self.file else None   
       
class TransferOrder(models.Model):
    STATUS_CHOICES = [
        ('cloud_connected', 'Cloud Connected'),
        ('files_selected', 'Files Selected'),
        ('storage_selected', 'Storage Selected'),
        ('payment_completed', 'Payment Completed'),
        ('payment_pending', 'Payment Pending'),
        ('download_in_progress', 'Download In Progress'),
        ('download_completed', 'Download Completed'),
        ('download_failed', 'Download Failed'),
        ('download_partial', 'Download Partial'),
        ('processing', 'Processing Files'),
        ('shipped', 'Shipped'),
        ('delivered', 'Delivered'),
        ('completed', 'Completed'),
        ('cancelled', 'Cancelled')
    ]
    
    CLOUD_SOURCE_CHOICES = [
        ('google_drive', 'Google Drive'),
        ('dropbox', 'Dropbox'),
        ('onedrive', 'OneDrive'),
        ('local_upload', 'Local Upload') 
    ]
        
    STORAGE_CHOICES = [
        ('flash_drive', 'USB Flash Drive'),
        ('memory_card', 'Memory Card'),
        ('external_hdd', 'External HDD')
    ]
    
    # UUID primary key for better scalability and security
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
        unique=True
    )
    
    # Public-facing order number (shorter, more user-friendly)
    order_number = models.CharField(
        max_length=20,
        unique=True,
        editable=False,
        blank=True,
        help_text="Public order number for customer reference"
    )
    
    user = models.ForeignKey(
        User, 
        on_delete=models.CASCADE,
        related_name='transfer_orders'
    )
    
    cloud_source = models.CharField(
        max_length=20, 
        choices=CLOUD_SOURCE_CHOICES, 
        default='google_drive'
    )
    
    # Access token for cloud API calls
    access_token = models.TextField(
        null=True, 
        blank=True,
        help_text="OAuth access token for cloud provider"
    )
    
      # Access token for cloud API calls
    refresh_token = models.TextField(
        null=True, 
        blank=True,
        help_text="OAuth access token for cloud provider"
    )
    
    token_expiry = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the access token expires"
    )
    
    status = models.CharField(
        max_length=50, 
        choices=STATUS_CHOICES, 
        default='cloud_connected'
    )
    
    storage_type = models.CharField(
        max_length=50, 
        choices=STORAGE_CHOICES, 
        null=True, 
        blank=True
    )
    
    storage_size = models.CharField(
        max_length=20, 
        null=True, 
        blank=True
    )
    
    shipping_address = models.TextField(
        null=True, 
        blank=True
    )
    
    # Store selected files as JSON for faster retrieval
    selected_files = models.JSONField(
        default=list,
        help_text="List of selected files with metadata"
    )
    
    total_files = models.IntegerField(
        default=0
    )
    
    total_size = models.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        default=0.00,  # in GB
        help_text="Total size of selected files in GB"
    )
    
    # Payment information
    payment_method = models.CharField(
        max_length=50, 
        null=True, 
        blank=True
    )
    
    payment_amount = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0.00,
        help_text="Amount paid for the order"
    )
    
    payment_currency = models.CharField(
        max_length=3,
        default='KES',
        help_text="Currency code (KES, USD, etc.)"
    )
    
    # Download tracking
    download_started_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the download process started"
    )
    
    download_completed_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the download process completed"
    )
    
    download_status = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        help_text="Current download status message"
    )
    
    download_log = models.JSONField(
        null=True,
        blank=True,
        help_text="Detailed download log with file statuses"
    )
    
    # Timestamps with timezone support
    created_at = models.DateTimeField(
        auto_now_add=True
    )
    
    updated_at = models.DateTimeField(
        auto_now=True
    )
    
 
    
    
    # Add these to your TransferOrder model
    download_started_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the download process started"
    )

    download_completed_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the download process completed"
    )

    retry_count = models.IntegerField(
        default=0,
        help_text="Number of times download has been retried"
    )
    
    # Estimated completion time
    estimated_completion = models.DateTimeField(
        null=True,
        blank=True,
        help_text="Estimated completion time for the order"
    )
    
    class Meta:
        verbose_name = _("Transfer Order")
        verbose_name_plural = _("Transfer Orders")
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user', 'status']),
            models.Index(fields=['status', 'created_at']),
            models.Index(fields=['order_number']),
            models.Index(fields=['created_at']),
            models.Index(fields=['user', 'created_at']),
        ]
    
    def __str__(self):
        return f"Order {self.order_number} - {self.user.email} - {self.status}"
    
    def save(self, *args, **kwargs):
        # Generate order number if not set
        if not self.order_number:
            self.order_number = self._generate_order_number()
        
        # Update timestamps based on status changes
        if self.status in ['payment_completed', 'download_completed']:
            self.estimated_completion = timezone.now() + timezone.timedelta(hours=24)
        
        super().save(*args, **kwargs)
    
    def _generate_order_number(self):
        """Generate a unique, user-friendly order number"""
        import random
        import string
        
        # Format: TRANS-XXXXXX (6 random alphanumeric characters)
        while True:
            random_chars = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
            order_num = f"TRANS-{random_chars}"
            
            if not TransferOrder.objects.filter(order_number=order_num).exists():
                return order_num
    
    @property
    def display_id(self):
        """Public-facing order ID (shorter than UUID)"""
        return self.order_number
    
    @property
    def is_downloadable(self):
        """Check if order is ready for download"""
        return self.status in ['payment_completed', 'storage_selected']
    
    @property
    def requires_payment(self):
        """Check if order requires payment"""
        return self.status in ['storage_selected', 'payment_pending']

class FileSelection(models.Model):
    # UUID primary key
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
        unique=True
    )
    
    order = models.ForeignKey(
        TransferOrder, 
        on_delete=models.CASCADE, 
        related_name='file_selections'
    )
    
    file_id = models.CharField(
        max_length=255,
        help_text="Cloud provider's file ID"
    )
    
    file_name = models.CharField(
        max_length=500
    )
    downloaded_filename = models.CharField(
        max_length=500, 
        blank=True, null=True)
    
    file_path = models.TextField(
        blank=True, 
        null=True,
        help_text="Full path of the file in cloud storage"
    )
    
    file_size = models.BigIntegerField(
        default=0,
        help_text="Size in bytes"
    )
    
    file_size_gb = models.DecimalField(
        max_digits=10,
        decimal_places=6,
        default=0.000000,
        help_text="Size in GB (calculated field)"
    )
    
    mime_type = models.CharField(
        max_length=100, 
        blank=True, 
        null=True
    )
    
    cloud_source = models.CharField(
        max_length=20, 
        default='google_drive'
    )
    
    # Download status for individual files
    download_size = models.BigIntegerField(
        null=True,
        blank=True,
        help_text="Actual downloaded size in bytes"
        )

    download_attempts = models.IntegerField(
        default=0,
        help_text="Number of download attempts"
    )

    download_status = models.CharField(
        max_length=20,
        choices=[
            ('pending', 'Pending'),
            ('downloading', 'Downloading'),
            ('downloaded', 'Downloaded'),
            ('failed', 'Failed'),
            ('skipped', 'Skipped')
        ],
        default='pending'
    )
    
    download_error = models.TextField(
        blank=True,
        null=True,
        help_text="Error message if download failed"
    )
    
    selected_at = models.DateTimeField(
        auto_now_add=True
    )
    
    downloaded_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the file was successfully downloaded"
    )
    
    #Added for linking to local uploaded files
    # Link to LocalUploadedFile if applicable
    
    local_file = models.ForeignKey(
        LocalUploadedFile,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='selections'
    )
    
    progress_percentage = models.IntegerField(default=0)  # Add this line

    
    class Meta:
        verbose_name = _("File Selection")
        verbose_name_plural = _("File Selections")
        ordering = ['-selected_at']
        unique_together = ['order', 'file_id']
        indexes = [
            models.Index(fields=['order', 'download_status']),
            models.Index(fields=['cloud_source', 'selected_at']),
            models.Index(fields=['download_status']),
        ]
    
    def __str__(self):
        return f"{self.file_name} ({self.file_size} bytes)"
    
    def save(self, *args, **kwargs):
        # Calculate file size in GB
        if self.file_size > 0:
            self.file_size_gb = self.file_size / (1024 ** 3)
        
        super().save(*args, **kwargs)
    
    @property
    def formatted_size(self):
        """Human-readable file size"""
        if self.file_size >= 1024 ** 3:  # GB
            return f"{self.file_size / (1024 ** 3):.2f} GB"
        elif self.file_size >= 1024 ** 2:  # MB
            return f"{self.file_size / (1024 ** 2):.2f} MB"
        elif self.file_size >= 1024:  # KB
            return f"{self.file_size / 1024:.2f} KB"
        else:
            return f"{self.file_size} bytes"