"""Serializers for the supplier portal."""

from __future__ import annotations

import base64
from decimal import Decimal

from rest_framework import serializers

from apps.suppliers.constants import FILE_TYPE_CHOICES


# ------------------------------------------------------------------- Documents

def _file_to_http_file(uploaded) -> dict:
    """Convert a Django UploadedFile to MyFatoorah's HttpFile shape."""
    content = uploaded.read()
    try:
        uploaded.seek(0)
    except Exception:
        pass
    return {
        "FileName": uploaded.name,
        "MediaType": getattr(uploaded, "content_type", "")
        or "application/octet-stream",
        "Buffer": base64.b64encode(content).decode("ascii"),
    }


class UploadDocumentSerializer(serializers.Serializer):
    """Multipart KYC document upload. MyFatoorah caps file size at 5 MB."""

    MAX_BYTES = 5 * 1024 * 1024
    ALLOWED_EXTENSIONS = {
        ".jpg", ".jpeg", ".png", ".bmp", ".gif",
        ".xls", ".xlsx", ".pdf", ".doc", ".docx",
    }

    file = serializers.FileField()
    file_type = serializers.ChoiceField(
        choices=[t[0] for t in FILE_TYPE_CHOICES]
    )
    expire_date = serializers.DateField(required=False)

    def validate_file(self, value):
        if value.size > self.MAX_BYTES:
            raise serializers.ValidationError(
                f"File too large. Max {self.MAX_BYTES // (1024 * 1024)} MB."
            )
        name = (value.name or "").lower()
        if not any(name.endswith(ext) for ext in self.ALLOWED_EXTENSIONS):
            raise serializers.ValidationError(
                "Unsupported file type. Allowed: "
                + ", ".join(sorted(self.ALLOWED_EXTENSIONS))
            )
        return value

    def to_payload(self, supplier_code: int) -> dict:
        data = self.validated_data
        payload: dict = {
            "FileUpload": _file_to_http_file(data["file"]),
            "FileType": data["file_type"],
            "SupplierCode": supplier_code,
        }
        if "expire_date" in data:
            payload["ExpireDate"] = data["expire_date"].strftime(
                "%Y-%m-%dT00:00:00"
            )
        return payload


# ------------------------------------------------------------------- Payments


class InvoiceItemSerializer(serializers.Serializer):
    """A single line item inside a SendPayment request."""

    item_name = serializers.CharField(max_length=255)
    quantity = serializers.IntegerField(min_value=1)
    unit_price = serializers.DecimalField(
        max_digits=12, decimal_places=2, min_value=Decimal("0")
    )


class SendPaymentSerializer(serializers.Serializer):
    """Validate supplier input and build the MyFatoorah SendPayment payload."""

    # Required
    customer_name = serializers.CharField(max_length=255)
    invoice_value = serializers.DecimalField(
        max_digits=12, decimal_places=2, min_value=Decimal("0.01")
    )
    notification_option = serializers.ChoiceField(choices=["LNK", "SMS", "EML", "ALL"])

    # Optional
    customer_email = serializers.EmailField(required=False, allow_blank=True)
    customer_mobile = serializers.CharField(max_length=20, required=False, allow_blank=True)
    mobile_country_code = serializers.CharField(max_length=5, required=False, allow_blank=True)
    display_currency_iso = serializers.CharField(max_length=3, required=False, default="AED")
    language = serializers.CharField(max_length=2, required=False, default="en")
    customer_reference = serializers.CharField(max_length=255, required=False, allow_blank=True)
    callback_url = serializers.URLField(required=False, allow_blank=True)
    error_url = serializers.URLField(required=False, allow_blank=True)
    invoice_items = InvoiceItemSerializer(many=True, required=False)

    def to_payload(self, supplier_code: int) -> dict:
        """Build the upstream MyFatoorah JSON body from validated data."""
        d = self.validated_data
        payload: dict = {
            "CustomerName": d["customer_name"],
            "InvoiceValue": float(d["invoice_value"]),
            "NotificationOption": d["notification_option"],
            "DisplayCurrencyIso": d.get("display_currency_iso", "AED"),
            "Language": d.get("language", "en"),
            "Suppliers": [
                {
                    "SupplierCode": supplier_code,
                    "InvoiceShare": float(d["invoice_value"]),
                    "ProposedShare": float(d["invoice_value"]),
                }
            ],
        }

        if d.get("customer_email"):
            payload["CustomerEmail"] = d["customer_email"]
        if d.get("customer_mobile"):
            payload["CustomerMobile"] = d["customer_mobile"]
        if d.get("mobile_country_code"):
            payload["MobileCountryCode"] = d["mobile_country_code"]
        if d.get("customer_reference"):
            payload["CustomerReference"] = d["customer_reference"]
        if d.get("callback_url"):
            payload["CallBackUrl"] = d["callback_url"]
        if d.get("error_url"):
            payload["ErrorUrl"] = d["error_url"]
        if d.get("invoice_items"):
            payload["InvoiceItems"] = [
                {
                    "ItemName": item["item_name"],
                    "Quantity": item["quantity"],
                    "UnitPrice": float(item["unit_price"]),
                }
                for item in d["invoice_items"]
            ]

        return payload


# ----------------------------------------------------------------- Refund status

REFUND_STATUS_KEY_TYPES = ("InvoiceId", "RefundReference", "RefundId")


class RefundStatusSerializer(serializers.Serializer):
    """Look up refund status by InvoiceId / RefundReference / RefundId."""

    key = serializers.CharField(max_length=64)
    key_type = serializers.ChoiceField(choices=REFUND_STATUS_KEY_TYPES)


# ----------------------------------------------------------------- Admin: link

class LinkSupplierSerializer(serializers.Serializer):
    """Admin: link a portal user to an existing MyFatoorah supplier."""

    user_id = serializers.IntegerField()
    supplier_code = serializers.IntegerField(min_value=1)


# ----------------------------------------------------------------- Transactions


def map_payment_status(invoice_id: str, data: dict) -> dict:
    """Flatten a GetPaymentStatus response into a transaction-row shape.

    Mirrors the columns of the MyFatoorah Orders List: reference, customer,
    value, status, payment method, card, etc.
    """
    if not isinstance(data, dict):
        return {"invoice_id": str(invoice_id), "status": "Unknown"}

    txns = data.get("InvoiceTransactions") or []
    last = txns[-1] if txns else {}
    card = (last.get("Card") or {}) if isinstance(last, dict) else {}

    return {
        "invoice_id": str(data.get("InvoiceId", invoice_id)),
        "invoice_reference": data.get("InvoiceReference"),
        "customer_reference": data.get("CustomerReference"),
        "created_date": data.get("CreatedDate"),
        "expiry_date": data.get("ExpiryDate"),
        "customer_name": data.get("CustomerName"),
        "customer_mobile": data.get("CustomerMobile"),
        "customer_email": data.get("CustomerEmail"),
        "invoice_value": data.get("InvoiceValue"),
        "invoice_display_value": data.get("InvoiceDisplayValue"),
        "status": data.get("InvoiceStatus"),
        "deposit_status": data.get("DepositStatus"),
        "payment_method": last.get("PaymentGateway") if last else None,
        "transaction_date": last.get("TransactionDate") if last else None,
        "transaction_status": last.get("TransactionStatus") if last else None,
        "card_number": card.get("Number") or None,
        "card_brand": card.get("Brand") or None,
    }
