import uuid 
from django.db import models
from django.core.exceptions import ValidationError
from django.utils import timezone
from django_softdelete.models import SoftDeleteModel, SoftDeleteManager
from inventory.models import Item
from tickets.models import IssueThread

class Shipment(SoftDeleteModel):
    # State choices
    CREATED = 'CREATED'
    PENDING_REVIEW = 'PENDING_REVIEW'
    READY_FOR_SHIPPING = 'READY_FOR_SHIPPING'
    REJECTED = 'REJECTED'
    SHIPPED = 'SHIPPED'
    COMPLETED = 'COMPLETED'
    
    SHIPMENT_STATES = [
        (CREATED, 'Created'),
        (PENDING_REVIEW, 'Pending Review'),
        (READY_FOR_SHIPPING, 'Ready for Shipping'),
        (REJECTED, 'Rejected'),
        (SHIPPED, 'Shipped'),
        (COMPLETED, 'Completed'),
    ]

    # Review requirement choices
    REVIEW_ITEMS = 'ITEMS'
    REVIEW_ADDRESS = 'ADDRESS'
    REVIEW_BOTH = 'BOTH'
    
    REVIEW_REQUIREMENTS = [
        (REVIEW_ITEMS, 'Items Review Required'),
        (REVIEW_ADDRESS, 'Address Review Required'),
        (REVIEW_BOTH, 'Both Items and Address Review Required'),
    ]

    id = models.AutoField(primary_key=True)
    public_secret = models.UUIDField(default=uuid.uuid4)
    state = models.CharField(
        max_length=20,
        choices=SHIPMENT_STATES,
        default=CREATED
    )
    review_requirement = models.CharField(
        max_length=10,
        choices=REVIEW_REQUIREMENTS,
        null=True,
        blank=True
    )

    # Shipping address fields
    recipient_name = models.CharField(max_length=255, blank=True, default='')
    address_supplements = models.TextField(max_length=255, blank=True, default='')
    street_address = models.CharField(max_length=255, blank=True, default='')
    city = models.CharField(max_length=100, blank=True, default='')
    state_province = models.CharField(max_length=100, blank=True, default='')
    postal_code = models.CharField(max_length=20, blank=True, default='')
    country = models.CharField(max_length=100, blank=True, default='')

    related_items = models.ManyToManyField(Item)
    related_tickets = models.ManyToManyField(IssueThread)

    created_at = models.DateTimeField(null=True, auto_now_add=True)
    updated_at = models.DateTimeField(blank=True, null=True)
    shipped_at = models.DateTimeField(blank=True, null=True)
    completed_at = models.DateTimeField(blank=True, null=True)

    all_objects = models.Manager()

    def __str__(self):
        return f'[{self.id}] {self.state}'

    def clean(self):
        """Validate state transitions and required fields"""
        if not self.pk:  # New instance
            return

        old_instance = Shipment.objects.get(pk=self.pk)
        
        # Validate state transitions
        valid_transitions = {
            self.CREATED: [self.PENDING_REVIEW],
            self.PENDING_REVIEW: [self.READY_FOR_SHIPPING, self.REJECTED],
            self.READY_FOR_SHIPPING: [self.SHIPPED],
            self.SHIPPED: [self.COMPLETED],
            self.REJECTED: [],  # No transitions from rejected
            self.COMPLETED: [],  # No transitions from completed
        }

        if (self.state != old_instance.state and 
            self.state not in valid_transitions[old_instance.state]):
            raise ValidationError(f'Invalid state transition from {old_instance.state} to {self.state}')

        # Validate review requirement when entering PENDING_REVIEW
        if self.state == self.PENDING_REVIEW and old_instance.state == self.CREATED:
            if not self.review_requirement:
                raise ValidationError('Review requirement must be specified when entering PENDING_REVIEW state')

        # Validate required fields based on state and review requirement
        if self.state in [self.READY_FOR_SHIPPING, self.SHIPPED, self.COMPLETED]:
            if not all([self.recipient_name, self.street_address, self.city, 
                       self.state_province, self.postal_code, self.country]):
                raise ValidationError('All address fields are required for shipping')

        if self.state != self.CREATED and not self.related_items.exists():
            raise ValidationError('Shipment must have at least one item')

    def add_items(self, review_requirement):
        """Move shipment to PENDING_REVIEW after items are added"""
        if self.state == self.CREATED and self.related_items.exists():
            if not review_requirement:
                raise ValidationError('Review requirement must be specified when adding items')
            if review_requirement not in [self.REVIEW_ITEMS, self.REVIEW_ADDRESS, self.REVIEW_BOTH]:
                raise ValidationError(f'Invalid review requirement: {review_requirement}')
            
            self.review_requirement = review_requirement
            self.state = self.PENDING_REVIEW
            self.save()

    def approve(self):
        """Approve shipment for shipping"""
        if self.state == self.PENDING_REVIEW:
            # Validate that all required reviews are completed
            if self.review_requirement == self.REVIEW_ITEMS and not self.related_items.exists():
                raise ValidationError('Items must be added before approval')
            elif self.review_requirement == self.REVIEW_ADDRESS and not all([self.recipient_name, self.street_address, self.city, 
                                                                          self.state_province, self.postal_code, self.country]):
                raise ValidationError('Address must be complete before approval')
            elif self.review_requirement == self.REVIEW_BOTH:
                if not self.related_items.exists():
                    raise ValidationError('Items must be added before approval')
                if not all([self.recipient_name, self.street_address, self.city, 
                          self.state_province, self.postal_code, self.country]):
                    raise ValidationError('Address must be complete before approval')
            
            self.state = self.READY_FOR_SHIPPING
            self.save()

    def reject(self):
        """Reject shipment"""
        if self.state == self.PENDING_REVIEW:
            self.state = self.REJECTED
            self.save()

    def mark_shipped(self):
        """Mark shipment as shipped"""
        if self.state == self.READY_FOR_SHIPPING:
            self.state = self.SHIPPED
            self.shipped_at = timezone.now()
            self.save()

    def mark_completed(self):
        """Mark shipment as completed"""
        if self.state == self.SHIPPED:
            self.state = self.COMPLETED
            self.completed_at = timezone.now()
            self.save()

    def save(self, *args, **kwargs):
        self.clean()
        super().save(*args, **kwargs)