# app/modules/payments/services/gateway_service.py
"""
Gateway service for managing payment gateway configurations.

This service handles:
- Gateway configuration and credentials
- Gateway health checks
- Gateway-specific operations

Each gateway has its own implementation that conforms to the
gateway protocol.

Usage:
    from app.modules.payments.services import GatewayService

    gateway_service = GatewayService()

    # Get available gateways
    gateways = gateway_service.get_available_gateways()

    # Check gateway status
    status = await gateway_service.check_gateway_health("stripe")
"""

import logging
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum
from typing import Any, Protocol

logger = logging.getLogger(__name__)


class GatewayStatus(str, Enum):
    """Gateway operational status."""

    ACTIVE = "active"
    INACTIVE = "inactive"
    ERROR = "error"
    MAINTENANCE = "maintenance"


@dataclass
class GatewayInfo:
    """Information about a payment gateway."""

    code: str
    name: str
    status: GatewayStatus
    enabled: bool
    supports_refunds: bool = True
    supports_recurring: bool = False
    supported_currencies: list[str] | None = None
    config: dict[str, Any] | None = None


class GatewayProtocol(Protocol):
    """Protocol that all gateway implementations must follow."""

    @property
    def code(self) -> str:
        """Gateway code identifier."""
        ...

    @property
    def name(self) -> str:
        """Gateway display name."""
        ...

    async def process_payment(
        self,
        amount: int,
        currency: str,
        payment_method: str,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Process a payment."""
        ...

    async def refund(
        self,
        transaction_id: str,
        amount: int | None = None,
    ) -> dict[str, Any]:
        """Issue a refund."""
        ...

    async def health_check(self) -> bool:
        """Check if gateway is operational."""
        ...


class BaseGateway(ABC):
    """Base class for gateway implementations."""

    @property
    @abstractmethod
    def code(self) -> str:
        """Gateway code identifier."""

    @property
    @abstractmethod
    def name(self) -> str:
        """Gateway display name."""

    @abstractmethod
    async def process_payment(
        self,
        amount: int,
        currency: str,
        payment_method: str,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Process a payment."""

    @abstractmethod
    async def refund(
        self,
        transaction_id: str,
        amount: int | None = None,
    ) -> dict[str, Any]:
        """Issue a refund."""

    async def health_check(self) -> bool:
        """Check if gateway is operational."""
        return True


class StripeGateway(BaseGateway):
    """Stripe payment gateway implementation."""

    @property
    def code(self) -> str:
        return "stripe"

    @property
    def name(self) -> str:
        return "Stripe"

    async def process_payment(
        self,
        amount: int,
        currency: str,
        payment_method: str,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Process a payment through Stripe."""
        # TODO: Implement Stripe payment processing
        logger.info(f"Processing Stripe payment: {amount} {currency}")
        return {
            "success": True,
            "transaction_id": f"pi_mock_{amount}",
            "gateway": self.code,
        }

    async def refund(
        self,
        transaction_id: str,
        amount: int | None = None,
    ) -> dict[str, Any]:
        """Issue a refund through Stripe."""
        # TODO: Implement Stripe refund
        logger.info(f"Processing Stripe refund for {transaction_id}")
        return {
            "success": True,
            "refund_id": f"re_mock_{transaction_id}",
        }


class PayPalGateway(BaseGateway):
    """PayPal payment gateway implementation."""

    @property
    def code(self) -> str:
        return "paypal"

    @property
    def name(self) -> str:
        return "PayPal"

    async def process_payment(
        self,
        amount: int,
        currency: str,
        payment_method: str,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Process a payment through PayPal."""
        # TODO: Implement PayPal payment processing
        logger.info(f"Processing PayPal payment: {amount} {currency}")
        return {
            "success": True,
            "transaction_id": f"paypal_mock_{amount}",
            "gateway": self.code,
        }

    async def refund(
        self,
        transaction_id: str,
        amount: int | None = None,
    ) -> dict[str, Any]:
        """Issue a refund through PayPal."""
        # TODO: Implement PayPal refund
        logger.info(f"Processing PayPal refund for {transaction_id}")
        return {
            "success": True,
            "refund_id": f"paypal_refund_{transaction_id}",
        }


class BankTransferGateway(BaseGateway):
    """Bank transfer gateway implementation."""

    @property
    def code(self) -> str:
        return "bank_transfer"

    @property
    def name(self) -> str:
        return "Bank Transfer"

    async def process_payment(
        self,
        amount: int,
        currency: str,
        payment_method: str,
        **kwargs: Any,
    ) -> dict[str, Any]:
        """Record a bank transfer payment (manual verification)."""
        logger.info(f"Recording bank transfer: {amount} {currency}")
        return {
            "success": True,
            "transaction_id": f"bt_mock_{amount}",
            "gateway": self.code,
            "status": "pending_verification",
        }

    async def refund(
        self,
        transaction_id: str,
        amount: int | None = None,
    ) -> dict[str, Any]:
        """Record a bank transfer refund (manual process)."""
        logger.info(f"Recording bank transfer refund for {transaction_id}")
        return {
            "success": True,
            "refund_id": f"bt_refund_{transaction_id}",
            "status": "pending_manual",
        }


class GatewayService:
    """
    Service for managing payment gateway configurations.

    Provides a registry of available gateways and methods for
    gateway operations.
    """

    def __init__(self) -> None:
        self._gateways: dict[str, BaseGateway] = {
            "stripe": StripeGateway(),
            "paypal": PayPalGateway(),
            "bank_transfer": BankTransferGateway(),
        }
        self._enabled_gateways: set[str] = {"stripe", "bank_transfer"}

    def get_gateway(self, code: str) -> BaseGateway | None:
        """Get a gateway by code."""
        return self._gateways.get(code)

    def get_available_gateways(self) -> list[GatewayInfo]:
        """Get list of all available gateways with their status."""
        result = []
        for code, gateway in self._gateways.items():
            result.append(
                GatewayInfo(
                    code=code,
                    name=gateway.name,
                    status=GatewayStatus.ACTIVE if code in self._enabled_gateways else GatewayStatus.INACTIVE,
                    enabled=code in self._enabled_gateways,
                    supports_refunds=True,
                    supports_recurring=code == "stripe",
                    supported_currencies=["EUR", "USD", "GBP"] if code != "bank_transfer" else ["EUR"],
                )
            )
        return result

    def enable_gateway(self, code: str) -> bool:
        """Enable a gateway."""
        if code in self._gateways:
            self._enabled_gateways.add(code)
            logger.info(f"Enabled gateway: {code}")
            return True
        return False

    def disable_gateway(self, code: str) -> bool:
        """Disable a gateway."""
        if code in self._enabled_gateways:
            self._enabled_gateways.remove(code)
            logger.info(f"Disabled gateway: {code}")
            return True
        return False

    async def check_gateway_health(self, code: str) -> dict[str, Any]:
        """Check the health of a specific gateway."""
        gateway = self._gateways.get(code)
        if not gateway:
            return {"status": "unknown", "message": f"Gateway {code} not found"}

        try:
            is_healthy = await gateway.health_check()
            return {
                "status": "healthy" if is_healthy else "unhealthy",
                "gateway": code,
            }
        except Exception as e:  # noqa: EXC003
            logger.exception(f"Gateway health check failed: {code}")
            return {
                "status": "error",
                "gateway": code,
                "message": str(e),
            }

    async def check_all_gateways(self) -> list[dict[str, Any]]:
        """Check health of all enabled gateways."""
        results = []
        for code in self._enabled_gateways:
            result = await self.check_gateway_health(code)
            results.append(result)
        return results


# Singleton instance
gateway_service = GatewayService()

__all__ = [
    "GatewayService",
    "GatewayStatus",
    "GatewayInfo",
    "GatewayProtocol",
    "BaseGateway",
    "StripeGateway",
    "PayPalGateway",
    "BankTransferGateway",
    "gateway_service",
]
