"""
Billing Models for Credit System
"""
from decimal import Decimal
from django.db import models
from django.core.validators import MinValueValidator
from django.conf import settings
from igny8_core.auth.models import AccountBaseModel


class CreditTransaction(AccountBaseModel):
    """Track all credit transactions (additions, deductions)"""
    TRANSACTION_TYPE_CHOICES = [
        ('purchase', 'Purchase'),
        ('subscription', 'Subscription Renewal'),
        ('refund', 'Refund'),
        ('deduction', 'Usage Deduction'),
        ('adjustment', 'Manual Adjustment'),
    ]
    
    transaction_type = models.CharField(max_length=20, choices=TRANSACTION_TYPE_CHOICES, db_index=True)
    amount = models.IntegerField(help_text="Positive for additions, negative for deductions")
    balance_after = models.IntegerField(help_text="Credit balance after this transaction")
    description = models.CharField(max_length=255)
    metadata = models.JSONField(default=dict, help_text="Additional context (AI call details, etc.)")
    reference_id = models.CharField(
        max_length=255,
        blank=True,
        help_text="Optional reference (e.g., payment id, invoice id)"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        app_label = 'billing'
        db_table = 'igny8_credit_transactions'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['account', 'transaction_type']),
            models.Index(fields=['account', 'created_at']),
        ]
    
    def __str__(self):
        account = getattr(self, 'account', None)
        return f"{self.get_transaction_type_display()} - {self.amount} credits - {account.name if account else 'No Account'}"


class CreditUsageLog(AccountBaseModel):
    """Detailed log of credit usage per AI operation"""
    OPERATION_TYPE_CHOICES = [
        ('clustering', 'Keyword Clustering'),
        ('idea_generation', 'Content Ideas Generation'),
        ('content_generation', 'Content Generation'),
        ('image_generation', 'Image Generation'),
        ('reparse', 'Content Reparse'),
        ('ideas', 'Content Ideas Generation'),  # Legacy
        ('content', 'Content Generation'),  # Legacy
        ('images', 'Image Generation'),  # Legacy
    ]
    
    operation_type = models.CharField(max_length=50, choices=OPERATION_TYPE_CHOICES, db_index=True)
    credits_used = models.IntegerField(validators=[MinValueValidator(0)])
    cost_usd = models.DecimalField(max_digits=10, decimal_places=4, null=True, blank=True)
    model_used = models.CharField(max_length=100, blank=True)
    tokens_input = models.IntegerField(null=True, blank=True, validators=[MinValueValidator(0)])
    tokens_output = models.IntegerField(null=True, blank=True, validators=[MinValueValidator(0)])
    related_object_type = models.CharField(max_length=50, blank=True)  # 'keyword', 'cluster', 'task'
    related_object_id = models.IntegerField(null=True, blank=True)
    metadata = models.JSONField(default=dict)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        app_label = 'billing'
        db_table = 'igny8_credit_usage_logs'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['account', 'operation_type']),
            models.Index(fields=['account', 'created_at']),
            models.Index(fields=['account', 'operation_type', 'created_at']),
        ]
    
    def __str__(self):
        account = getattr(self, 'account', None)
        return f"{self.get_operation_type_display()} - {self.credits_used} credits - {account.name if account else 'No Account'}"


class CreditCostConfig(models.Model):
    """
    Configurable credit costs per AI function
    Admin-editable alternative to hardcoded constants
    """
    # Operation identification
    operation_type = models.CharField(
        max_length=50,
        unique=True,
        choices=CreditUsageLog.OPERATION_TYPE_CHOICES,
        help_text="AI operation type"
    )
    
    # Cost configuration
    credits_cost = models.IntegerField(
        validators=[MinValueValidator(0)],
        help_text="Credits required for this operation"
    )
    
    # Unit of measurement
    UNIT_CHOICES = [
        ('per_request', 'Per Request'),
        ('per_100_words', 'Per 100 Words'),
        ('per_200_words', 'Per 200 Words'),
        ('per_item', 'Per Item'),
        ('per_image', 'Per Image'),
    ]
    
    unit = models.CharField(
        max_length=50,
        default='per_request',
        choices=UNIT_CHOICES,
        help_text="What the cost applies to"
    )
    
    # Metadata
    display_name = models.CharField(max_length=100, help_text="Human-readable name")
    description = models.TextField(blank=True, help_text="What this operation does")
    
    # Status
    is_active = models.BooleanField(default=True, help_text="Enable/disable this operation")
    
    # Audit fields
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    updated_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='credit_cost_updates',
        help_text="Admin who last updated"
    )
    
    # Change tracking
    previous_cost = models.IntegerField(
        null=True,
        blank=True,
        help_text="Cost before last update (for audit trail)"
    )
    
    class Meta:
        app_label = 'billing'
        db_table = 'igny8_credit_cost_config'
        verbose_name = 'Credit Cost Configuration'
        verbose_name_plural = 'Credit Cost Configurations'
        ordering = ['operation_type']
    
    def __str__(self):
        return f"{self.display_name} - {self.credits_cost} credits {self.unit}"
    
    def save(self, *args, **kwargs):
        # Track cost changes
        if self.pk:
            try:
                old = CreditCostConfig.objects.get(pk=self.pk)
                if old.credits_cost != self.credits_cost:
                    self.previous_cost = old.credits_cost
            except CreditCostConfig.DoesNotExist:
                pass
        super().save(*args, **kwargs)


class Invoice(AccountBaseModel):
    """
    Invoice for subscription or credit purchases
    Tracks billing invoices with line items and payment status
    """
    STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('pending', 'Pending'),
        ('paid', 'Paid'),
        ('void', 'Void'),
        ('uncollectible', 'Uncollectible'),
    ]
    
    invoice_number = models.CharField(max_length=50, unique=True, db_index=True)
    
    # Amounts
    subtotal = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    tax = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    total = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    currency = models.CharField(max_length=3, default='USD')
    
    # Status
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending', db_index=True)
    
    # Dates
    invoice_date = models.DateField(db_index=True)
    due_date = models.DateField()
    paid_at = models.DateTimeField(null=True, blank=True)
    
    # Line items
    line_items = models.JSONField(default=list, help_text="Invoice line items: [{description, amount, quantity}]")
    
    # Payment integration
    stripe_invoice_id = models.CharField(max_length=255, null=True, blank=True)
    payment_method = models.CharField(max_length=50, null=True, blank=True)
    billing_email = models.EmailField(null=True, blank=True)
    billing_period_start = models.DateTimeField(null=True, blank=True)
    billing_period_end = models.DateTimeField(null=True, blank=True)
    
    # Metadata
    notes = models.TextField(blank=True)
    metadata = models.JSONField(default=dict)
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        app_label = 'billing'
        db_table = 'igny8_invoices'
        ordering = ['-invoice_date', '-created_at']
        indexes = [
            models.Index(fields=['account', 'status']),
            models.Index(fields=['account', 'invoice_date']),
            models.Index(fields=['invoice_number']),
        ]
    
    def __str__(self):
        return f"Invoice {self.invoice_number} - {self.account.name if self.account else 'No Account'}"

    # ------------------------------------------------------------------
    # Helpers to keep service code working with legacy field names
    # ------------------------------------------------------------------
    @property
    def subtotal_amount(self):
        return self.subtotal

    @property
    def tax_amount(self):
        return self.tax

    @property
    def total_amount(self):
        return self.total

    def add_line_item(self, description: str, quantity: int, unit_price: Decimal, amount: Decimal = None):
        """Append a line item and keep JSON shape consistent."""
        items = list(self.line_items or [])
        qty = quantity or 1
        amt = Decimal(amount) if amount is not None else Decimal(unit_price) * qty
        items.append({
            'description': description,
            'quantity': qty,
            'unit_price': str(unit_price),
            'amount': str(amt),
        })
        self.line_items = items

    def calculate_totals(self):
        """Recompute subtotal, tax, and total from line_items."""
        subtotal = Decimal('0')
        for item in self.line_items or []:
            try:
                subtotal += Decimal(str(item.get('amount') or 0))
            except Exception:
                pass
        self.subtotal = subtotal
        self.total = subtotal + (self.tax or Decimal('0'))


class Payment(AccountBaseModel):
    """
    Payment record for invoices
    Supports: Stripe, PayPal, Manual (Bank Transfer, Local Wallet)
    """
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('pending_approval', 'Pending Approval'),
        ('processing', 'Processing'),
        ('succeeded', 'Succeeded'),
        ('completed', 'Completed'),  # Legacy alias for succeeded
        ('failed', 'Failed'),
        ('refunded', 'Refunded'),
        ('cancelled', 'Cancelled'),
    ]
    
    PAYMENT_METHOD_CHOICES = [
        ('stripe', 'Stripe (Credit/Debit Card)'),
        ('paypal', 'PayPal'),
        ('bank_transfer', 'Bank Transfer (Manual)'),
        ('local_wallet', 'Local Wallet (Manual)'),
        ('manual', 'Manual Payment'),
    ]
    
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='payments')
    
    # Amount
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    currency = models.CharField(max_length=3, default='USD')
    
    # Status
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending', db_index=True)
    
    # Payment method
    payment_method = models.CharField(max_length=50, choices=PAYMENT_METHOD_CHOICES, db_index=True)
    
    # Stripe integration
    stripe_payment_intent_id = models.CharField(max_length=255, null=True, blank=True)
    stripe_charge_id = models.CharField(max_length=255, null=True, blank=True)
    
    # PayPal integration
    paypal_order_id = models.CharField(max_length=255, null=True, blank=True)
    paypal_capture_id = models.CharField(max_length=255, null=True, blank=True)
    
    # Manual payment details
    manual_reference = models.CharField(
        max_length=255,
        blank=True,
        help_text="Bank transfer reference, wallet transaction ID, etc."
    )
    manual_notes = models.TextField(blank=True, help_text="Admin notes for manual payments")
    transaction_reference = models.CharField(max_length=255, blank=True)
    admin_notes = models.TextField(blank=True, help_text="Internal notes on approval/rejection")
    approved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='approved_payments'
    )
    approved_at = models.DateTimeField(null=True, blank=True)
    
    # Timestamps
    processed_at = models.DateTimeField(null=True, blank=True)
    failed_at = models.DateTimeField(null=True, blank=True)
    refunded_at = models.DateTimeField(null=True, blank=True)
    
    # Error tracking
    failure_reason = models.TextField(blank=True)
    
    # Metadata
    metadata = models.JSONField(default=dict)
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        app_label = 'billing'
        db_table = 'igny8_payments'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['account', 'status']),
            models.Index(fields=['account', 'payment_method']),
            models.Index(fields=['invoice', 'status']),
        ]
    
    def __str__(self):
        return f"Payment {self.id} - {self.get_payment_method_display()} - {self.amount} {self.currency}"


class CreditPackage(models.Model):
    """
    One-time credit purchase packages
    Defines available credit bundles for purchase
    """
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True, db_index=True)
    
    # Credits
    credits = models.IntegerField(validators=[MinValueValidator(1)])
    
    # Pricing
    price = models.DecimalField(max_digits=10, decimal_places=2)
    discount_percentage = models.IntegerField(default=0, help_text="Discount percentage (0-100)")
    
    # Stripe
    stripe_product_id = models.CharField(max_length=255, null=True, blank=True)
    stripe_price_id = models.CharField(max_length=255, null=True, blank=True)
    
    # PayPal
    paypal_plan_id = models.CharField(max_length=255, null=True, blank=True)
    
    # Status
    is_active = models.BooleanField(default=True, db_index=True)
    is_featured = models.BooleanField(default=False, help_text="Show as featured package")
    
    # Display
    description = models.TextField(blank=True)
    features = models.JSONField(default=list, help_text="Bonus features or highlights")
    
    # Sort order
    sort_order = models.IntegerField(default=0, help_text="Display order (lower = first)")
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        app_label = 'billing'
        db_table = 'igny8_credit_packages'
        ordering = ['sort_order', 'price']
    
    def __str__(self):
        return f"{self.name} - {self.credits} credits - ${self.price}"


class PaymentMethodConfig(models.Model):
    """
    Configure payment methods availability per country
    Allows enabling/disabling manual payments by region
    """
    PAYMENT_METHOD_CHOICES = [
        ('stripe', 'Stripe'),
        ('paypal', 'PayPal'),
        ('bank_transfer', 'Bank Transfer'),
        ('local_wallet', 'Local Wallet'),
    ]
    
    country_code = models.CharField(
        max_length=2,
        db_index=True,
        help_text="ISO 2-letter country code (e.g., US, GB, IN)"
    )
    payment_method = models.CharField(max_length=50, choices=PAYMENT_METHOD_CHOICES)
    is_enabled = models.BooleanField(default=True)
    
    # Display info
    display_name = models.CharField(max_length=100, blank=True)
    instructions = models.TextField(blank=True, help_text="Payment instructions for users")
    
    # Manual payment details (for bank_transfer/local_wallet)
    bank_name = models.CharField(max_length=255, blank=True)
    account_number = models.CharField(max_length=255, blank=True)
    routing_number = models.CharField(max_length=255, blank=True)
    swift_code = models.CharField(max_length=255, blank=True)
    
    # Additional fields for local wallets
    wallet_type = models.CharField(max_length=100, blank=True, help_text="E.g., PayTM, PhonePe, etc.")
    wallet_id = models.CharField(max_length=255, blank=True)
    
    # Order/priority
    sort_order = models.IntegerField(default=0)
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        app_label = 'billing'
        db_table = 'igny8_payment_method_config'
        unique_together = [['country_code', 'payment_method']]
        ordering = ['country_code', 'sort_order']
        verbose_name = 'Payment Method Configuration'
        verbose_name_plural = 'Payment Method Configurations'
    
    def __str__(self):
        return f"{self.country_code} - {self.get_payment_method_display()}"


class AccountPaymentMethod(AccountBaseModel):
    """
    Account-scoped payment methods (Stripe/PayPal/manual bank/wallet).
    Only metadata/refs are stored here; no secrets.
    """
    PAYMENT_METHOD_CHOICES = [
        ('stripe', 'Stripe'),
        ('paypal', 'PayPal'),
        ('bank_transfer', 'Bank Transfer'),
        ('local_wallet', 'Local Wallet'),
    ]

    type = models.CharField(max_length=50, choices=PAYMENT_METHOD_CHOICES, db_index=True)
    display_name = models.CharField(max_length=100, help_text="User-visible label", default='')
    is_default = models.BooleanField(default=False, db_index=True)
    is_enabled = models.BooleanField(default=True, db_index=True)
    is_verified = models.BooleanField(default=False, db_index=True)
    country_code = models.CharField(max_length=2, blank=True, default='', help_text="ISO-2 country code (optional)")

    # Manual/bank/local wallet details (non-sensitive metadata)
    instructions = models.TextField(blank=True, default='')
    metadata = models.JSONField(default=dict, blank=True, help_text="Provider references or display metadata")

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

    class Meta:
        app_label = 'billing'
        db_table = 'igny8_account_payment_methods'
        ordering = ['-is_default', 'display_name', 'id']
        indexes = [
            models.Index(fields=['account', 'is_default']),
            models.Index(fields=['account', 'type']),
        ]
        unique_together = [['account', 'display_name']]

    def __str__(self):
        return f"{self.account_id} - {self.display_name} ({self.type})"
