from decimal import Decimal

from django.conf import settings
from django.db import models
from django.utils import timezone


class WalletAccount(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='wallet_account',
    )
    balance = models.DecimalField(max_digits=14, decimal_places=2, default=Decimal('0.00'))
    currency = models.CharField(max_length=3, default='USD')
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Wallet account'

    def __str__(self):
        return f'Wallet {self.user_id}: {self.balance} {self.currency}'


class LedgerEntry(models.Model):
    class EntryType(models.TextChoices):
        WALLET_DEBIT_PAYMENT = 'WALLET_DEBIT_PAYMENT', 'Wallet debit (shipment payment)'
        WALLET_CREDIT_EARNING = 'WALLET_CREDIT_EARNING', 'Wallet credit (trip earning)'
        WALLET_CREDIT_TOPUP = 'WALLET_CREDIT_TOPUP', 'Wallet credit (top-up)'
        CREDIT_EARNING = 'CREDIT_EARNING', 'Credit terms earning (transporter credit)'
        WITHDRAWAL_DEBIT = 'WITHDRAWAL_DEBIT', 'Withdrawal debit'
        ADJUSTMENT = 'ADJUSTMENT', 'Manual adjustment'

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='ledger_entries',
    )
    amount = models.DecimalField(
        max_digits=14,
        decimal_places=2,
        help_text='Signed: positive adds to wallet balance, negative subtracts.',
    )
    entry_type = models.CharField(max_length=40, choices=EntryType.choices)
    trip = models.ForeignKey(
        'core.Trip',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='ledger_entries',
    )
    payment = models.ForeignKey(
        'billing.Payment',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='ledger_entries',
    )
    idempotency_key = models.CharField(max_length=128, blank=True, db_index=True)
    note = models.CharField(max_length=255, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user', '-created_at']),
        ]

    def __str__(self):
        return f'Ledger {self.user_id} {self.amount} {self.entry_type}'


class Payment(models.Model):
    class Method(models.TextChoices):
        WALLET = 'WALLET', 'Wallet'
        CARD = 'CARD', 'Card'
        CASH = 'CASH', 'Cash'
        CREDIT = 'CREDIT', 'Credit terms'

    class Status(models.TextChoices):
        PENDING = 'PENDING', 'Pending'
        REQUIRES_ACTION = 'REQUIRES_ACTION', 'Requires client action'
        PROCESSING = 'PROCESSING', 'Processing'
        CAPTURED = 'CAPTURED', 'Captured'
        FAILED = 'FAILED', 'Failed'
        REFUNDED = 'REFUNDED', 'Refunded'
        PENDING_COD = 'PENDING_COD', 'Cash on delivery pending collection'

    trip = models.ForeignKey('core.Trip', on_delete=models.CASCADE, related_name='payments')
    payer = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='payments_made',
    )
    payee = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='payments_received',
    )
    method = models.CharField(max_length=20, choices=Method.choices)
    amount = models.DecimalField(max_digits=14, decimal_places=2)
    currency = models.CharField(max_length=3, default='USD')
    status = models.CharField(max_length=30, choices=Status.choices, default=Status.PENDING)
    provider_ref = models.CharField(max_length=255, blank=True)
    idempotency_key = models.CharField(max_length=128, blank=True)
    metadata = models.JSONField(default=dict, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']


class Invoice(models.Model):
    class Status(models.TextChoices):
        DRAFT = 'DRAFT', 'Draft'
        ISSUED = 'ISSUED', 'Issued'
        PAID = 'PAID', 'Paid'
        VOID = 'VOID', 'Void'

    number = models.CharField(max_length=32, unique=True)
    trip = models.ForeignKey('core.Trip', on_delete=models.CASCADE, related_name='invoices')
    shipper = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='invoices',
    )
    line_items = models.JSONField(default=list)
    tax = models.DecimalField(max_digits=14, decimal_places=2, default=Decimal('0.00'))
    total = models.DecimalField(max_digits=14, decimal_places=2)
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.ISSUED)
    payment = models.ForeignKey(
        Payment,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='invoices',
    )
    is_archived = models.BooleanField(default=False)
    archived_at = models.DateTimeField(null=True, blank=True)
    due_date = models.DateField(null=True, blank=True)
    issued_at = models.DateTimeField(default=timezone.now)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-issued_at']


class WithdrawalRequest(models.Model):
    class Status(models.TextChoices):
        PENDING = 'PENDING', 'Pending'
        APPROVED = 'APPROVED', 'Approved'
        REJECTED = 'REJECTED', 'Rejected'
        PAID = 'PAID', 'Paid'

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='withdrawal_requests',
    )
    amount = models.DecimalField(max_digits=14, decimal_places=2)
    currency = models.CharField(max_length=3, default='USD')
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.PENDING)
    note = models.CharField(max_length=500, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']
