from decimal import Decimal
import random
import string
from django.utils.text import slugify
from django.utils import timezone
from django.conf import settings
from django.core.validators import MinValueValidator
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
from common.choices import NATIONALITY_CHOICES, COUNTRY_CHOICES, LANGUAGE_CHOICES
from django.core.exceptions import ValidationError
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
import os

def validate_affiliate_profile_image(image):
    ext = os.path.splitext(image.name)[1].lower()
    allowed_extensions = ['.jpg', '.jpeg', '.png', '.webp']
    if ext not in allowed_extensions:
        raise ValidationError("Only JPG, JPEG, PNG, or WEBP images are allowed.")

class AffiliateProfile(models.Model):
    STATUS_CHOICES = [
        ('pending', 'Pending Approval'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
        ('inactive', 'Inactive'),
    ]

    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='affiliate_profile'
    )

    affiliate_code = models.CharField(
        max_length=30,
        unique=True,
        blank=True,
        help_text="Unique affiliate tracking code."
    )

    full_name = models.CharField(max_length=150)
    phone = models.CharField(max_length=30, blank=True)
    whatsapp = models.CharField(max_length=30, blank=True)
    country = models.CharField(max_length=100, blank=True)

    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending'
    )

    # Profile photo with validation
    profile_photo = models.ImageField(
        upload_to='affiliate_photos/',
        blank=True,
        null=True,
        validators=[validate_affiliate_profile_image],
        help_text="Profile picture for your affiliate account."
    )

    is_active = models.BooleanField(default=True)

    bank_name = models.CharField(max_length=150, blank=True)
    bank_account_name = models.CharField(max_length=150, blank=True)
    bank_account_number = models.CharField(max_length=100, blank=True)
    bank_branch = models.CharField(max_length=150, blank=True)
    payout_notes = models.TextField(blank=True)

    total_earned_usd = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        default=0,
        validators=[MinValueValidator(0)]
    )

    total_paid_usd = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        default=0,
        validators=[MinValueValidator(0)]
    )

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Affiliate Profile'
        verbose_name_plural = 'Affiliate Profiles'

    def __str__(self):
        return f"{self.full_name} - {self.affiliate_code}"

    def save(self, *args, **kwargs):
        if not self.affiliate_code:
            # 1. Build base from full_name (letters only, max 6 chars)
            name_slug = slugify(self.full_name).replace('-', '').upper()
            base = ''.join([c for c in name_slug if c.isalpha()])[:6]
            if len(base) < 3:
                base = 'AFF'   # fallback

            # 2. Generate unique code with retries
            max_attempts = 5
            for _ in range(max_attempts):
                random_suffix = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
                candidate = f"{base}{random_suffix}"
                if not AffiliateProfile.objects.filter(affiliate_code=candidate).exists():
                    self.affiliate_code = candidate
                    break
            else:
                # If still not unique (extremely rare), fallback to timestamp
                timestamp = timezone.now().strftime('%H%M%S')
                self.affiliate_code = f"{base}{timestamp}"

        super().save(*args, **kwargs)

        # Compress profile photo if present
        if self.profile_photo:
            self.compress_profile_photo()

    def compress_profile_photo(self):
        """
        Resize and compress profile photo to 600x600 max, convert to JPEG, quality 85.
        """
        try:
            img = Image.open(self.profile_photo.path)

            # Convert RGBA/P to RGB (JPEG doesn't support alpha)
            if img.mode in ('RGBA', 'P'):
                img = img.convert('RGB')

            max_width = 600
            max_height = 600
            img.thumbnail((max_width, max_height))

            buffer = BytesIO()
            img.save(buffer, format='JPEG', quality=85, optimize=True)

            file_name = os.path.splitext(os.path.basename(self.profile_photo.name))[0] + '.jpg'
            self.profile_photo.save(
                file_name,
                ContentFile(buffer.getvalue()),
                save=False
            )

            # Save the model again with the compressed image
            super().save(update_fields=['profile_photo'])

        except Exception:
            # Silently fail – do not break user experience
            pass

    @property
    def available_balance_usd(self):
        return self.total_earned_usd - self.total_paid_usd

    def get_affiliate_link(self):
        return reverse('expat_life:home') + f"?ref={self.affiliate_code}"
    
class AffiliateGuestReferral(models.Model):
    STATUS_CHOICES = [
        ('signed_up', 'Signed Up'),
        ('confirmed', 'Confirmed'),
        ('service_fee_paid', 'Service Fee Paid'),
        ('completed', 'Completed'),
        ('cancelled', 'Cancelled'),
    ]

    affiliate = models.ForeignKey(
        AffiliateProfile,
        on_delete=models.CASCADE,
        related_name='guest_referrals'
    )

    guest_user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='affiliate_guest_referrals'
    )

    foreigner_lead = models.ForeignKey(
        'expat_life.ForeignerLead',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='affiliate_referrals'
    )

    foreigner_profile = models.ForeignKey(
        'expat_life.ForeignerProfile',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='affiliate_referrals'
    )

    guest_name = models.CharField(max_length=150, blank=True)
    guest_email = models.EmailField(blank=True)
    guest_phone = models.CharField(max_length=30, blank=True)
    guest_country = models.CharField(max_length=100, blank=True)

    selected_package_name = models.CharField(max_length=150, blank=True)
    selected_package_amount_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0
    )

    possible_confirmation_commission_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0
    )

    possible_service_fee_commission_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0
    )

    total_possible_commission_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0
    )

    total_earned_commission_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0
    )

    status = models.CharField(
        max_length=30,
        choices=STATUS_CHOICES,
        default='signed_up'
    )

    notes = models.TextField(blank=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']
        unique_together = ('affiliate', 'guest_user')
        verbose_name = 'Affiliate Guest Referral'
        verbose_name_plural = 'Affiliate Guest Referrals'

    def __str__(self):
        return f"{self.affiliate} → {self.guest_name or self.guest_email}"
    
class AffiliateCommission(models.Model):
    COMMISSION_FOR_CHOICES = [
        ('guest_confirmation_fee', 'Guest Confirmation Fee'),
        ('guest_one_time_service_fee', 'Guest One-Time Service Fee'),
    ]

    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('earned', 'Earned'),
        ('paid', 'Paid'),
        ('cancelled', 'Cancelled'),
    ]

    affiliate = models.ForeignKey(
        AffiliateProfile,
        on_delete=models.CASCADE,
        related_name='commissions'
    )

    referral = models.ForeignKey(
        AffiliateGuestReferral,
        on_delete=models.CASCADE,
        related_name='commissions'
    )

    commission_for = models.CharField(
        max_length=50,
        choices=COMMISSION_FOR_CHOICES
    )

    source_amount_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)]
    )

    commission_percentage = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        default=20
    )

    commission_amount_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)]
    )

    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending'
    )

    earned_at = models.DateTimeField(null=True, blank=True)
    paid_at = models.DateTimeField(null=True, blank=True)

    notes = models.TextField(blank=True)

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']
        unique_together = ('referral', 'commission_for')
        verbose_name = 'Affiliate Commission'
        verbose_name_plural = 'Affiliate Commissions'

    def __str__(self):
        return f"{self.affiliate} - {self.commission_for} - ${self.commission_amount_usd}"
    
class AffiliatePayoutRequest(models.Model):
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('processing', 'Processing'),
        ('paid', 'Paid'),
        ('rejected', 'Rejected'),
        ('cancelled', 'Cancelled'),
    ]

    affiliate = models.ForeignKey(
        AffiliateProfile,
        on_delete=models.CASCADE,
        related_name='payout_requests'
    )

    amount_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(1)]
    )

    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending'
    )

    bank_snapshot = models.TextField(
        blank=True,
        help_text="Bank details at the time of payout request."
    )

    admin_notes = models.TextField(blank=True)

    requested_at = models.DateTimeField(auto_now_add=True)
    processed_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ['-requested_at']
        verbose_name = 'Affiliate Payout Request'
        verbose_name_plural = 'Affiliate Payout Requests'

    def __str__(self):
        return f"{self.affiliate} - ${self.amount_usd} - {self.status}"


    
class AffiliateBusinessCard(models.Model):
    """
    Stores a generated business card for an affiliate user.
    Each card is tied to a specific referral link and includes the QR code image
    and the final composite business card image.
    """

    affiliate_profile = models.ForeignKey(
        AffiliateProfile,  # Replace 'yourapp' with actual app name
        on_delete=models.CASCADE,
        related_name='business_cards'
    )
    referral_link = models.URLField(
        max_length=500,
        help_text="Full referral URL (including ?ref=CODE)"
    )
    qr_code_image = models.ImageField(
        upload_to='business_cards/qrcodes/',
        blank=True,
        null=True,
        help_text="Generated QR code image for this referral link"
    )
    business_card_image = models.ImageField(
        upload_to='business_cards/composites/',
        blank=True,
        null=True,
        help_text="Final composite business card image (with QR code, name, details)"
    )
    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(auto_now=True)

    # Optionally store design parameters or card title
    design_version = models.CharField(max_length=50, default='default', blank=True)
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = "Affiliate Business Card"
        verbose_name_plural = "Affiliate Business Cards"

    def __str__(self):
        return f"Card for {self.affiliate_profile.full_name} ({self.created_at.date()})"

    def delete_qr_and_card_files(self):
        """Helper to remove associated image files when deleting a record."""
        if self.qr_code_image:
            if os.path.isfile(self.qr_code_image.path):
                os.remove(self.qr_code_image.path)
        if self.business_card_image:
            if os.path.isfile(self.business_card_image.path):
                os.remove(self.business_card_image.path)

class AffiliateMarketingResource(models.Model):
    affiliate_profile = models.ForeignKey(
        'AffiliateProfile',
        on_delete=models.CASCADE,
        related_name='custom_marketing_resources'
    )
    title = models.CharField(max_length=200, help_text="Custom document title")
    language = models.CharField(max_length=2, choices=LANGUAGE_CHOICES, default='en')
    full_pdf_file = models.FileField(
        upload_to='affiliate_marketing/%Y/%m/',
        help_text="Custom brochure with affiliate info"
    )
    summary_overview_pdf = models.FileField(
        upload_to='affiliate_marketing/slides/%Y/%m/',
        blank=True,
        null=True,
        help_text="Optional slide deck PDF (presentation format)"
    )
    presentation_pdf = models.FileField(
        upload_to='affiliate_marketing/slides/%Y/%m/',
        blank=True,
        null=True,
        help_text="Optional slide deck PDF (presentation format)"
    )
    description = models.TextField(blank=True, help_text="Optional description or notes")
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = "Affiliate Marketing Resource"
        verbose_name_plural = "Affiliate Marketing Resources"

    def __str__(self):
        return f"{self.affiliate_profile.full_name} - {self.title} ({self.get_language_display()})"
    
class Language(models.Model):
    code = models.CharField(max_length=2, unique=True, choices=LANGUAGE_CHOICES)
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name
    
class AffiliateResourceRequest(models.Model):
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('in_progress', 'In Progress'),
        ('completed', 'Completed'),
        ('rejected', 'Rejected'),
    ]

    affiliate_profile = models.ForeignKey(
        'AffiliateProfile',
        on_delete=models.CASCADE,
        related_name='resource_requests'
    )
    requested_languages = models.JSONField(default=list)
    request_date = models.DateTimeField(default=timezone.now)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    admin_notes = models.TextField(blank=True, help_text="Internal notes for admin response")
    response_message = models.TextField(blank=True, help_text="Message to send to affiliate (e.g., estimated delivery time)")
    responded_at = models.DateTimeField(blank=True, null=True)
    responded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='handled_resource_requests'
    )
    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-request_date']
        verbose_name = "Affiliate Resource Request"
        verbose_name_plural = "Affiliate Resource Requests"


class AffiliateTrainingResource(models.Model):
    LANGUAGE_CHOICES = [
        ('en', 'English'),
        ('si', 'Sinhala'),
        ('ta', 'Tamil'),
    ]

    language = models.CharField(
        max_length=2,
        choices=LANGUAGE_CHOICES,
        default='en',
        unique=True
    )

    title = models.CharField(
        max_length=200,
        default="The Ensolanka Global Ambassador Playbook"
    )

    full_playbook_pdf = models.FileField(
        upload_to='affiliate_training/playbooks/%Y/%m/',
        blank=True,
        null=True
    )

    summary_overview_pdf = models.FileField(
        upload_to='affiliate_training/summaries/%Y/%m/',
        blank=True,
        null=True
    )

    audio_guide_file = models.FileField(
        upload_to='affiliate_training/audio/%Y/%m/',
        blank=True,
        null=True
    )

    youtube_video_link = models.URLField(
        blank=True,
        null=True
    )

    description = models.TextField(blank=True)

    is_active = models.BooleanField(default=True)

    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['language']
        verbose_name = "Affiliate Training Resource"
        verbose_name_plural = "Affiliate Training Resources"

    def __str__(self):
        return f"{self.get_language_display()} - {self.title}"