"""Provider-agnostic payment domain (V2 §2.6, §6, §7.3, §14.3).

These models exist independently of any payment provider so the money core can
be built and tested before AzamPay is wired. The AzamPay adapter will later fill
`provider`/`provider_ref` and drive the state machines via the webhook inbox.
"""

from uuid import uuid4

from django.db import models


class FeeSchedule(models.Model):
    """Effective-dated fee configuration. No hard-coded fees in code/clients."""

    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(max_length=120)
    percent_bps = models.PositiveIntegerField(default=0, help_text="Fee percent in basis points (100 = 1%).")
    flat_fee = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    min_fee = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    currency = models.CharField(max_length=3, default="TZS")
    effective_from = models.DateTimeField()
    effective_to = models.DateTimeField(null=True, blank=True)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "fee_schedules"
        ordering = ["-effective_from"]

    def __str__(self):
        return f"{self.name} ({self.percent_bps}bps + {self.flat_fee})"


class IdempotencyKey(models.Model):
    """Replay-safe handling for money-moving commands (V2 §14.3)."""

    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    key = models.CharField(max_length=120, unique=True, db_index=True)
    scope = models.CharField(max_length=80)
    reference = models.CharField(max_length=120, blank=True, default="")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "idempotency_keys"

    def __str__(self):
        return f"{self.scope}:{self.key}"


class PaymentAttempt(models.Model):
    class Status(models.TextChoices):
        CREATED = "created", "Created"
        PENDING = "pending", "Pending"
        SUCCEEDED = "succeeded", "Succeeded"
        FAILED = "failed", "Failed"
        EXPIRED = "expired", "Expired"
        REVERSED = "reversed", "Reversed"

    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    deal = models.ForeignKey("escrow.Deal", on_delete=models.CASCADE, related_name="payment_attempts")
    amount = models.DecimalField(max_digits=15, decimal_places=2)
    currency = models.CharField(max_length=3, default="TZS")
    status = models.CharField(max_length=12, choices=Status.choices, default=Status.CREATED, db_index=True)
    provider = models.CharField(max_length=40, blank=True, default="")
    provider_ref = models.CharField(max_length=120, null=True, blank=True, unique=True)
    idempotency_key = models.CharField(max_length=120, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "payment_attempts"
        ordering = ["-created_at"]

    def __str__(self):
        return f"attempt {self.id} ({self.status})"


class Payout(models.Model):
    class Status(models.TextChoices):
        QUEUED = "queued", "Queued"
        SUBMITTED = "submitted", "Submitted"
        PROCESSING = "processing", "Processing"
        SUCCEEDED = "succeeded", "Succeeded"
        FAILED_RETRYABLE = "failed_retryable", "Failed (retryable)"
        FAILED_FINAL = "failed_final", "Failed (final)"

    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    deal = models.ForeignKey("escrow.Deal", on_delete=models.CASCADE, related_name="payouts")
    seller = models.ForeignKey("core.User", on_delete=models.SET_NULL, related_name="payouts", null=True, blank=True)
    amount = models.DecimalField(max_digits=15, decimal_places=2)
    currency = models.CharField(max_length=3, default="TZS")
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.QUEUED, db_index=True)
    provider = models.CharField(max_length=40, blank=True, default="")
    provider_ref = models.CharField(max_length=120, null=True, blank=True)
    # The ledger journal reference/idempotency_key to use once this payout is
    # confirmed (differs for a plain release vs. a split resolution) — set
    # when the disbursement is submitted, read back by
    # payments.views.azampay_disbursement_callback so it posts the correct
    # journal regardless of which flow created this payout.
    journal_reference = models.CharField(max_length=120, blank=True, default="")
    idempotency_key = models.CharField(max_length=120, blank=True, default="")
    retry_count = models.PositiveSmallIntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "payouts"
        ordering = ["-created_at"]

    def __str__(self):
        return f"payout {self.amount} ({self.status})"


class Refund(models.Model):
    class Status(models.TextChoices):
        REQUESTED = "requested", "Requested"
        APPROVED = "approved", "Approved"
        SUBMITTED = "submitted", "Submitted"
        PROCESSING = "processing", "Processing"
        COMPLETED = "completed", "Completed"
        FAILED = "failed", "Failed"

    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    deal = models.ForeignKey("escrow.Deal", on_delete=models.CASCADE, related_name="refunds")
    buyer = models.ForeignKey("core.User", on_delete=models.SET_NULL, related_name="refunds", null=True, blank=True)
    amount = models.DecimalField(max_digits=15, decimal_places=2)
    currency = models.CharField(max_length=3, default="TZS")
    status = models.CharField(max_length=12, choices=Status.choices, default=Status.REQUESTED, db_index=True)
    reason = models.CharField(max_length=255, blank=True, default="")
    provider = models.CharField(max_length=40, blank=True, default="")
    provider_ref = models.CharField(max_length=120, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "refunds"
        ordering = ["-created_at"]

    def __str__(self):
        return f"refund {self.amount} ({self.status})"


class ProviderWebhookEvent(models.Model):
    """Inbox for provider callbacks — replay-safe (V2 §16)."""

    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    provider = models.CharField(max_length=40)
    event_id = models.CharField(max_length=160, unique=True, db_index=True)
    event_type = models.CharField(max_length=80, blank=True, default="")
    payload = models.JSONField(default=dict, blank=True)
    signature_valid = models.BooleanField(default=False)
    processed = models.BooleanField(default=False)
    received_at = models.DateTimeField(auto_now_add=True)
    processed_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        db_table = "provider_webhook_events"
        ordering = ["-received_at"]

    def __str__(self):
        return f"{self.provider}:{self.event_id}"
