"""Payment provider abstraction (V2 §6.2).

Domain code depends only on this interface, never on a provider's request/response
shapes. The AzamPay adapter will implement this later; until then `ManualProvider`
lets the escrow flow run end-to-end in development.
"""

from __future__ import annotations

import abc
from dataclasses import dataclass
from decimal import Decimal


@dataclass
class CollectionIntent:
    deal_code: str
    amount: Decimal
    currency: str
    payer_phone: str
    reference: str
    # MNO name (Airtel/Tigo/Halopesa/Mpesa/Azampesa), from the client's chosen
    # payment method. If empty, the provider resolves one from payer_phone.
    provider: str = ""


@dataclass
class DisbursementInstruction:
    payee_phone: str
    amount: Decimal
    currency: str
    reference: str
    # MNO name for the payout destination. If empty, the provider resolves
    # one from payee_phone.
    provider: str = ""


@dataclass
class ProviderResult:
    reference: str
    status: str          # normalized: pending | succeeded | failed
    provider_ref: str
    raw: dict


class PaymentProvider(abc.ABC):
    name: str = "base"

    @abc.abstractmethod
    def create_collection(self, intent: CollectionIntent) -> ProviderResult: ...

    @abc.abstractmethod
    def get_collection_status(self, provider_ref: str) -> ProviderResult: ...

    @abc.abstractmethod
    def create_disbursement(self, instruction: DisbursementInstruction) -> ProviderResult: ...

    @abc.abstractmethod
    def get_disbursement_status(self, provider_ref: str) -> ProviderResult: ...

    @abc.abstractmethod
    def create_refund(self, instruction: DisbursementInstruction) -> ProviderResult: ...

    @abc.abstractmethod
    def verify_callback(self, request) -> bool:
        """Return True only if the callback is authentic (signature/secret)."""

    @abc.abstractmethod
    def normalize_callback(self, payload: dict) -> ProviderResult:
        """Map a provider payload to a normalized ProviderResult."""
