"""
Payment Client Interface and Implementation
This module provides an abstraction layer for payment providers to make the system payment-agnostic
"""

import abc
from typing import Dict, Any, Optional
from dataclasses import dataclass
from datetime import datetime


@dataclass
class PaymentCustomer:
    id: str
    email: str
    name: str
    created_at: datetime


@dataclass
class PaymentMethod:
    id: str
    type: str
    brand: Optional[str] = None
    last4: Optional[str] = None
    exp_month: Optional[int] = None
    exp_year: Optional[int] = None


@dataclass
class Subscription:
    id: str
    customer_id: str
    plan_id: str
    status: str  # active, canceled, past_due, etc.
    current_period_start: datetime
    current_period_end: datetime
    created_at: datetime
    billing_cycle_anchor: Optional[datetime] = None
    cancel_at_period_end: Optional[bool] = None
    # 3DS Authentication fields
    payment_intent_id: Optional[str] = None
    payment_intent_status: Optional[str] = None
    payment_intent_client_secret: Optional[str] = None
    requires_action: Optional[bool] = None
    trial_end: Optional[datetime] = None
    billing_interval: Optional[str] = None


@dataclass
class Invoice:
    id: str
    customer_id: str
    subscription_id: str
    amount: float
    currency: str
    status: str  # draft, open, paid, void, etc.
    created_at: datetime
    due_date: Optional[datetime] = None
    description: Optional[str] = None
    invoice_pdf: Optional[str] = None  # URL to PDF invoice
    hosted_invoice_url: Optional[str] = None  # URL to hosted invoice page


class PaymentProvider(abc.ABC):
    """
    Abstract base class for payment providers.
    All payment providers should implement this interface.
    """
    
    @abc.abstractmethod
    async def create_customer(self, customer_data: Dict[str, Any]) -> PaymentCustomer:
        """
        Create a customer in the payment provider system
        """
        pass

    @abc.abstractmethod
    async def create_subscription(self, customer_id: str, plan_id: str, payment_method_id: str, trial_period_days: Optional[int] = None) -> Subscription:
        """
        Create a subscription for a customer
        """
        pass

    @abc.abstractmethod
    async def update_payment_method(self, customer_id: str, payment_method_id: str) -> PaymentMethod:
        """
        Update the payment method for a customer
        """
        pass

    @abc.abstractmethod
    async def cancel_subscription(
        self,
        subscription_id: str,
        cancel_at_period_end: bool = True
    ) -> Subscription:
        """
        Cancel a subscription

        Args:
            subscription_id: Subscription ID to cancel
            cancel_at_period_end: If True, cancel at end of billing period. Default True.
        """
        pass

    @abc.abstractmethod
    async def get_invoices(self, customer_id: str) -> list[Invoice]:
        """
        Get invoices for a customer
        """
        pass

    @abc.abstractmethod
    async def get_subscription(self, subscription_id: str) -> Subscription:
        """
        Get subscription details
        """
        pass

    @abc.abstractmethod
    async def get_customer(self, customer_id: str) -> PaymentCustomer:
        """
        Get customer details
        """
        pass

    @abc.abstractmethod
    async def create_setup_intent(self) -> Dict[str, Any]:
        """
        Create a setup intent for saving payment methods
        """
        pass

    @abc.abstractmethod
    async def create_payment_intent(self, amount: float, currency: str, customer_id: str, payment_method_id: str) -> Dict[str, Any]:
        """
        Create a payment intent for one-time payments
        """
        pass
