"""
BIAPAY SDK Models
"""

from dataclasses import dataclass, field
from typing import Optional


@dataclass
class ClientDetails:
    """Details about the originating client/channel.

    Attributes:
        originated_by: Channel identifier. Use "2" for web/iframe integrations.
    """
    originated_by: str = "2"

    def to_dict(self) -> dict:
        return {"originatedBy": self.originated_by}


@dataclass
class CustomerDetails:
    """Customer information for the payment session.

    Attributes:
        email: Customer email address.
        mobile_number: Customer mobile number (with country code).
    """
    email: str
    mobile_number: str

    def to_dict(self) -> dict:
        return {
            "email": self.email,
            "mobileNumber": self.mobile_number,
        }


@dataclass
class OrderDetails:
    """Order information for the payment session.

    Attributes:
        order_id: Your unique order identifier.
        amount: Payment amount (integer, e.g. 5000 for 5000 XAF).
        currency_code: ISO 4217 currency code (e.g. "XAF", "USD").
    """
    order_id: str
    amount: int
    currency_code: str

    def to_dict(self) -> dict:
        return {
            "orderId": self.order_id,
            "amount": self.amount,
            "currencyCode": self.currency_code,
        }


@dataclass
class PaymentSession:
    """Represents a BIAPAY payment session returned after authentication.

    Attributes:
        access_token: JWT token for this payment session.
        url: Base iframe URL.
        launch_url: Full iframe URL with Authorization token embedded.
                    Use this as the `src` of your <iframe> element.
    """
    access_token: str
    url: str
    launch_url: str

    def get_iframe_url(self, lang: Optional[str] = None) -> str:
        """Get the iframe URL, optionally with a language parameter.

        Args:
            lang: Language code for localization. Currently only "fr" is supported.

        Returns:
            The launch URL, with `&lang=<lang>` appended if specified.

        Example::

            url = session.get_iframe_url(lang="fr")
            # Returns: "https://payment.biapay.net/...&lang=fr"
        """
        url = self.launch_url
        if lang:
            url = f"{url}&lang={lang}"
        return url

    def get_iframe_html(self, lang: Optional[str] = None, **attrs) -> str:
        """Generate a ready-to-use HTML <iframe> tag for embedding the payment form.

        Args:
            lang: Language code for localization ("fr" supported).
            **attrs: Additional HTML attributes (width, height, style, etc.).

        Returns:
            An HTML string with the <iframe> element.

        Example::

            html = session.get_iframe_html(
                lang="fr",
                width="100%",
                height="600",
                style="border:none;"
            )
        """
        src = self.get_iframe_url(lang=lang)
        default_attrs = {
            "src": src,
            "width": "100%",
            "height": "600",
            "frameborder": "0",
            "allowfullscreen": "true",
        }
        default_attrs.update(attrs)
        attr_str = " ".join(f'{k}="{v}"' for k, v in default_attrs.items())
        return f"<iframe {attr_str}></iframe>"

    @classmethod
    def from_response(cls, data: dict) -> "PaymentSession":
        """Build a PaymentSession from the raw API response dict."""
        return cls(
            access_token=data["accessToken"],
            url=data["url"],
            launch_url=data["launchUrl"],
        )

    def __repr__(self):
        return (
            f"PaymentSession(url={self.url!r}, "
            f"launch_url={self.launch_url[:60]!r}...)"
        )


@dataclass
class CallbackPayload:
    """Represents the callback data sent by BIAPAY after a payment.

    Attributes:
        order_id: Your original order ID.
        status: Payment status, e.g. "COMPLETED" or "FAILED".
        currency: Currency code of the transaction.
        amount: Transaction amount.
        biapay_transaction_id: BIAPAY's internal transaction reference.
        transaction_id: Your original transaction ID.
        biapay_signature: HMAC signature for verification.
    """
    order_id: str
    status: str
    currency: str
    amount: str
    biapay_transaction_id: str
    transaction_id: str
    biapay_signature: Optional[str] = None

    @property
    def is_completed(self) -> bool:
        """Returns True if the payment was completed successfully."""
        return self.status.upper() == "COMPLETED"

    @property
    def is_failed(self) -> bool:
        """Returns True if the payment failed."""
        return not self.is_completed

    @classmethod
    def from_query_params(cls, params: dict) -> "CallbackPayload":
        """Build a CallbackPayload from URL query parameters (e.g. request.GET).

        Args:
            params: Dictionary of query string parameters from the callback URL.

        Returns:
            A CallbackPayload instance.

        Example (Django)::

            payload = CallbackPayload.from_query_params(request.GET)

        Example (Flask)::

            payload = CallbackPayload.from_query_params(request.args)
        """
        return cls(
            order_id=params.get("orderId", ""),
            status=params.get("status", ""),
            currency=params.get("currency", ""),
            amount=params.get("amount", ""),
            biapay_transaction_id=params.get("biapayTransactionId", ""),
            transaction_id=params.get("transactionId", ""),
            biapay_signature=params.get("biapaySignature"),
        )

    def __repr__(self):
        return (
            f"CallbackPayload(order_id={self.order_id!r}, "
            f"status={self.status!r}, amount={self.amount!r})"
        )
