from __future__ import annotations

import logging
from typing import Any

import httpx

from spherepay_mcp.adapters.reliability import ReliabilityPolicy
from spherepay_mcp.config import EnvironmentConfig
from spherepay_mcp.interfaces.route_config import SENSITIVE_FIELDS

logger = logging.getLogger(__name__)


def _redact(payload: dict[str, Any] | None) -> dict[str, Any] | None:
    """Return a shallow copy with sensitive field values replaced by '***'."""
    if payload is None:
        return None
    redacted = {}
    for k, v in payload.items():
        if k in SENSITIVE_FIELDS:
            redacted[k] = "***"
        elif isinstance(v, dict):
            redacted[k] = _redact(v)
        elif isinstance(v, list):
            redacted[k] = [_redact(item) if isinstance(item, dict) else item for item in v]
        else:
            redacted[k] = v
    return redacted


class OpenApiSpherePayGateway:
    """HTTP adapter implementing SpherePayGateway protocol via httpx."""

    def __init__(self, config: EnvironmentConfig, policy: ReliabilityPolicy | None = None):
        self._config = config
        self._policy = policy or ReliabilityPolicy(
            max_retries=config.max_retries,
            timeout=config.timeout_seconds,
        )
        self._client = httpx.AsyncClient(
            base_url=config.base_url,
            headers={
                "Authorization": f"Bearer {config.api_key}",
                "Content-Type": "application/json",
            },
        )

    async def close(self) -> None:
        await self._client.aclose()

    async def _request(
        self,
        method: str,
        path: str,
        *,
        json_body: dict[str, Any] | None = None,
        params: dict[str, Any] | None = None,
        headers: dict[str, str] | None = None,
    ) -> dict[str, Any]:
        clean_params = {k: v for k, v in (params or {}).items() if v is not None}
        logger.debug("%s %s params=%s body=%s", method, path, clean_params or None, _redact(json_body))
        return await self._policy.execute(
            self._client,
            method,
            path,
            json_body=json_body,
            params=clean_params or None,
            headers=headers,
        )

    # --- Customers ---

    async def create_customer(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v2/customer", json_body=payload)

    async def get_customer(self, customer_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v2/customer/{customer_id}")

    async def list_customers(self, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", "/v2/customer", params=params)

    async def patch_customer(self, customer_id: str, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("PATCH", f"/v2/customer/{customer_id}", json_body=payload)

    async def generate_tos_link(self, customer_id: str) -> dict[str, Any]:
        return await self._request("POST", f"/v2/customer/{customer_id}/tos-link")

    async def generate_kyc_link(self, customer_id: str) -> dict[str, Any]:
        return await self._request("POST", f"/v2/customer/{customer_id}/kyc-link")

    async def send_otp(self, customer_id: str, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", f"/v2/customer/{customer_id}/otp-send", json_body=payload)

    async def verify_otp(self, customer_id: str, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", f"/v2/customer/{customer_id}/otp-verify", json_body=payload)

    async def generate_face_verification_link(self, customer_id: str) -> dict[str, Any]:
        return await self._request("POST", f"/v2/customer/{customer_id}/face-verification-link")

    async def submit_verification(self, customer_id: str) -> dict[str, Any]:
        return await self._request("POST", f"/v2/customer/{customer_id}/submit-verification")

    # --- Bank Accounts ---

    async def create_bank_account(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v2/bank-account", json_body=payload)

    async def get_bank_account(self, bank_account_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v2/bank-account/{bank_account_id}")

    async def list_bank_accounts(self, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", "/v2/bank-account", params=params)

    async def delete_bank_account(self, bank_account_id: str) -> dict[str, Any]:
        return await self._request("DELETE", f"/v2/bank-account/{bank_account_id}")

    async def update_bank_account(self, bank_account_id: str, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("PATCH", f"/v2/bank-account/{bank_account_id}", json_body=payload)

    # --- Wallets ---

    async def create_wallet(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v2/wallet", json_body=payload)

    async def get_wallet(self, wallet_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v2/wallet/{wallet_id}")

    async def list_wallets(self, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", "/v2/wallet", params=params)

    async def delete_wallet(self, wallet_id: str) -> dict[str, Any]:
        return await self._request("DELETE", f"/v2/wallet/{wallet_id}")

    # --- Transfers ---

    async def create_transfer(self, payload: dict[str, Any], idempotency_key: str | None = None) -> dict[str, Any]:
        headers = {}
        if idempotency_key:
            headers["Idempotency-Key"] = idempotency_key
        return await self._request("POST", "/v2/transfer", json_body=payload, headers=headers or None)

    async def get_transfer(self, transfer_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v2/transfer/{transfer_id}")

    async def list_transfers(self, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", "/v2/transfer", params=params)

    async def cancel_transfer(self, transfer_id: str) -> dict[str, Any]:
        return await self._request("DELETE", f"/v2/transfer/{transfer_id}")

    # --- Documents ---

    async def upload_document(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v2/document", json_body=payload)

    # --- Business Representatives ---

    async def create_business_rep(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v2/business-representative", json_body=payload)

    async def get_business_rep(self, rep_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v2/business-representative/{rep_id}")

    async def list_business_reps(self, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", "/v2/business-representative", params=params)

    async def patch_business_rep(self, rep_id: str, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("PATCH", f"/v2/business-representative/{rep_id}", json_body=payload)

    async def delete_business_rep(self, rep_id: str) -> dict[str, Any]:
        return await self._request("DELETE", f"/v2/business-representative/{rep_id}")

    async def generate_rep_face_verification_link(self, rep_id: str) -> dict[str, Any]:
        return await self._request("POST", f"/v2/business-representative/{rep_id}/face-verification-link")

    async def submit_rep_verification(self, rep_id: str) -> dict[str, Any]:
        return await self._request("POST", f"/v2/business-representative/{rep_id}/submit-verification")

    # --- Offloader Wallets ---

    async def create_offloader_wallet(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v2/offloader-wallet", json_body=payload)

    async def get_offloader_wallet(self, wallet_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v2/offloader-wallet/{wallet_id}")

    async def list_offloader_wallets(self, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", "/v2/offloader-wallet", params=params)

    async def update_offloader_wallet(self, wallet_id: str, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("PATCH", f"/v2/offloader-wallet/{wallet_id}", json_body=payload)

    # --- Virtual Accounts ---

    async def create_virtual_account(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v2/virtual-account", json_body=payload)

    async def get_virtual_account(self, virtual_account_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v2/virtual-account/{virtual_account_id}")

    async def list_virtual_accounts(self, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", "/v2/virtual-account", params=params)

    async def update_virtual_account(self, virtual_account_id: str, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("PATCH", f"/v2/virtual-account/{virtual_account_id}", json_body=payload)

    async def deactivate_virtual_account(self, virtual_account_id: str) -> dict[str, Any]:
        return await self._request("PATCH", f"/v2/virtual-account/{virtual_account_id}/deactivate")

    async def reactivate_virtual_account(self, virtual_account_id: str) -> dict[str, Any]:
        return await self._request("PATCH", f"/v2/virtual-account/{virtual_account_id}/reactivate")

    async def list_virtual_account_transfers(self, virtual_account_id: str, params: dict[str, Any]) -> dict[str, Any]:
        return await self._request("GET", f"/v2/virtual-account/{virtual_account_id}/transfer", params=params)

    # --- Webhooks --- (v1 API)

    async def create_webhook(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v1/webhook", json_body=payload)

    async def get_webhook(self, webhook_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v1/webhook/{webhook_id}")

    # --- Events --- (v1 API)

    async def get_event(self, event_id: str) -> dict[str, Any]:
        return await self._request("GET", f"/v1/event/{event_id}")

    # --- CCTP --- (v1 API)

    async def submit_cctp_offramp(self, payload: dict[str, Any]) -> dict[str, Any]:
        return await self._request("POST", "/v1/cctp/off-ramp", json_body=payload)
