import uuid
from django.conf import settings
from django.db import models
from django.utils import timezone


def delivery_photo_upload_path(instance, filename):
    return f"escrow/delivery/{instance.escrow.id}/{filename}"


class EscrowTransaction(models.Model):
    """One escrow record per vendor order — holds payment until delivery confirmed."""

    STATUS_INITIATED = "initiated"
    STATUS_PAYMENT_PENDING = "payment_pending"
    STATUS_HELD = "held"
    STATUS_DELIVERY_PENDING = "delivery_pending"
    STATUS_DELIVERY_UPLOADED = "delivery_uploaded"
    STATUS_BUYER_CONFIRMED = "buyer_confirmed"
    STATUS_RELEASED = "released"
    STATUS_DISPUTED = "disputed"
    STATUS_AUTO_RELEASED = "auto_released"
    STATUS_REFUNDED = "refunded"

    STATUS_CHOICES = [
        (STATUS_INITIATED, "Initiated"),
        (STATUS_PAYMENT_PENDING, "Payment Pending"),
        (STATUS_HELD, "Funds Held"),
        (STATUS_DELIVERY_PENDING, "Awaiting Delivery"),
        (STATUS_DELIVERY_UPLOADED, "Delivery Uploaded"),
        (STATUS_BUYER_CONFIRMED, "Buyer Confirmed"),
        (STATUS_RELEASED, "Released to Seller"),
        (STATUS_DISPUTED, "Disputed"),
        (STATUS_AUTO_RELEASED, "Auto-Released (48h)"),
        (STATUS_REFUNDED, "Refunded to Buyer"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    # Links
    order = models.ForeignKey(
        "cart.Order", on_delete=models.CASCADE, related_name="escrow_transactions"
    )
    vendor_order = models.OneToOneField(
        "cart.VendorOrder", on_delete=models.CASCADE, related_name="escrow"
    )
    vendor = models.ForeignKey(
        "vendors.Vendor", on_delete=models.CASCADE, related_name="escrow_transactions"
    )
    buyer = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="escrow_purchases",
    )

    # Amounts — always GHS
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    currency = models.CharField(max_length=10, default="GHS")
    platform_fee = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    seller_payout = models.DecimalField(max_digits=10, decimal_places=2, default=0)

    # Paystack
    paystack_reference = models.CharField(max_length=200, blank=True, default="", db_index=True)
    paystack_access_code = models.CharField(max_length=200, blank=True, default="")
    paystack_authorization_url = models.URLField(blank=True, default="")
    paystack_charge_id = models.CharField(max_length=200, blank=True, default="")
    paystack_transfer_code = models.CharField(max_length=200, blank=True, default="")

    status = models.CharField(
        max_length=30, choices=STATUS_CHOICES, default=STATUS_INITIATED, db_index=True
    )

    # Delivery
    delivery_note = models.TextField(blank=True, default="")
    delivery_confirmed_at = models.DateTimeField(null=True, blank=True)

    # Buyer confirmation
    buyer_confirmation_token = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True)
    buyer_confirmed_at = models.DateTimeField(null=True, blank=True)
    buyer_session_key = models.CharField(max_length=200, blank=True, default="")

    # Auto-release
    auto_release_after = models.DateTimeField(null=True, blank=True)

    # Payout
    payout_initiated_at = models.DateTimeField(null=True, blank=True)
    payout_completed_at = models.DateTimeField(null=True, blank=True)

    # Meta
    dispute_note = models.TextField(blank=True, default="")
    admin_notes = models.TextField(blank=True, default="")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Escrow Transaction"
        verbose_name_plural = "Escrow Transactions"

    def __str__(self):
        return f"Escrow {str(self.id)[:8]} — {self.vendor.store_name} — GHS {self.amount}"

    def compute_fees(self):
        """Compute platform fee (2%) and seller payout. Adjustable in settings."""
        fee_rate = getattr(settings, "ESCROW_PLATFORM_FEE_RATE", 0.02)
        self.platform_fee = round(float(self.amount) * fee_rate, 2)
        self.seller_payout = round(float(self.amount) - float(self.platform_fee), 2)

    @property
    def is_overdue_for_auto_release(self):
        if self.auto_release_after and self.status == self.STATUS_DELIVERY_UPLOADED:
            return timezone.now() >= self.auto_release_after
        return False


class EscrowDeliveryPhoto(models.Model):
    """One or more delivery proof photos per escrow transaction."""

    escrow = models.ForeignKey(
        EscrowTransaction, on_delete=models.CASCADE, related_name="delivery_photos"
    )
    photo = models.ImageField(upload_to=delivery_photo_upload_path)
    caption = models.CharField(max_length=300, blank=True, default="")
    uploaded_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["uploaded_at"]

    def __str__(self):
        return f"Delivery photo for {self.escrow}"


class EscrowLog(models.Model):
    """Immutable audit trail — one row per status change or notable event."""

    ACTION_CHOICES = [
        ("status_change", "Status Changed"),
        ("payment_received", "Payment Received"),
        ("delivery_uploaded", "Delivery Proof Uploaded"),
        ("buyer_confirmed", "Buyer Confirmed Receipt"),
        ("buyer_disputed", "Buyer Raised Dispute"),
        ("auto_released", "Auto-Released (48h timeout)"),
        ("payout_initiated", "Payout Initiated"),
        ("payout_completed", "Payout Completed"),
        ("sms_sent", "SMS Notification Sent"),
        ("admin_action", "Admin Action"),
        ("refunded", "Refunded"),
    ]

    escrow = models.ForeignKey(
        EscrowTransaction, on_delete=models.CASCADE, related_name="logs"
    )
    action = models.CharField(max_length=30, choices=ACTION_CHOICES)
    previous_status = models.CharField(max_length=30, blank=True, default="")
    new_status = models.CharField(max_length=30, blank=True, default="")
    note = models.TextField(blank=True, default="")
    actor = models.CharField(max_length=200, blank=True, default="system")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["created_at"]

    def __str__(self):
        return f"[{self.action}] {self.escrow_id} at {self.created_at:%Y-%m-%d %H:%M}"


class VendorPayoutAccount(models.Model):
    """Paystack recipient details for a vendor — used for disbursement."""

    BANK_TYPE = "nuban"
    MOBILE_MONEY_TYPE = "mobile_money"

    ACCOUNT_TYPE_CHOICES = [
        (BANK_TYPE, "Bank Account (NUBAN)"),
        (MOBILE_MONEY_TYPE, "Mobile Money"),
    ]

    vendor = models.OneToOneField(
        "vendors.Vendor", on_delete=models.CASCADE, related_name="payout_account"
    )
    account_type = models.CharField(
        max_length=20, choices=ACCOUNT_TYPE_CHOICES, default=BANK_TYPE
    )
    account_name = models.CharField(max_length=200)
    account_number = models.CharField(max_length=50)
    bank_code = models.CharField(max_length=20, blank=True, default="")
    mobile_network = models.CharField(max_length=20, blank=True, default="")

    # Paystack transfer recipient code
    paystack_recipient_code = models.CharField(max_length=200, blank=True, default="", db_index=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "Vendor Payout Account"

    def __str__(self):
        return f"{self.vendor.store_name} — {self.account_number}"