"""SpherePay MCP Server — composition root and entry point.

Wires config -> gateway -> services -> tools -> FastMCP server.
See ADR-0002 for architecture rationale.
"""

from __future__ import annotations

import asyncio
import atexit
import logging
import os

from fastmcp import FastMCP

from spherepay_mcp.adapters.logging_config import configure_logging
from spherepay_mcp.adapters.reliability import IdempotencyStrategy, ReliabilityPolicy
from spherepay_mcp.adapters.spherepay_client import OpenApiSpherePayGateway
from spherepay_mcp.application.business_rep import BusinessRepService
from spherepay_mcp.application.customer_onboarding import CustomerOnboardingService
from spherepay_mcp.application.funding_instrument import FundingInstrumentService
from spherepay_mcp.application.offloader_wallet import OffloaderWalletService
from spherepay_mcp.application.transfer_workflow import TransferWorkflowService
from spherepay_mcp.application.virtual_account import VirtualAccountService
from spherepay_mcp.config import EnvironmentConfig
from spherepay_mcp.interfaces.resources import register_resources
from spherepay_mcp.interfaces.tools import register_read_tools, register_workflow_tools

logger = logging.getLogger(__name__)


def create_server() -> FastMCP:
    """Build and return a fully-wired MCP server."""

    # Configure structured logging before anything else
    log_format = os.environ.get("SPHEREPAY_LOG_FORMAT", "text")
    log_level = os.environ.get("SPHEREPAY_LOG_LEVEL", "INFO")
    configure_logging(fmt=log_format, level=log_level)

    config = EnvironmentConfig.from_env()

    env_label = "SANDBOX" if config.is_sandbox else "PRODUCTION"
    logger.info("Initializing SpherePay MCP server (%s) -> %s", env_label, config.base_url)

    # Infrastructure
    policy = ReliabilityPolicy(
        max_retries=config.max_retries,
        timeout=config.timeout_seconds,
    )
    gateway = OpenApiSpherePayGateway(config, policy)

    # Ensure httpx client is closed on process exit
    def _shutdown_gateway() -> None:
        try:
            loop = asyncio.get_running_loop()
            loop.create_task(gateway.close())
        except RuntimeError:
            loop = asyncio.new_event_loop()
            loop.run_until_complete(gateway.close())
            loop.close()

    atexit.register(_shutdown_gateway)

    # Application services
    customer_svc = CustomerOnboardingService(gateway)
    funding_svc = FundingInstrumentService(gateway)
    transfer_svc = TransferWorkflowService(gateway, IdempotencyStrategy())
    business_rep_svc = BusinessRepService(gateway)
    virtual_account_svc = VirtualAccountService(gateway)
    offloader_wallet_svc = OffloaderWalletService(gateway)

    # MCP server
    mcp = FastMCP(
        name="SpherePay",
        instructions=(
            "SpherePay MCP server for managing customers, bank accounts, wallets, "
            "virtual accounts, offloader wallets, transfers, and webhooks. "
            "Use workflow tools (onboard_customer, verify_customer, setup_funding, execute_transfer, "
            "onboard_business_rep, setup_virtual_account, setup_offloader_wallet, create_webhook, "
            "submit_cctp_offramp) for multi-step operations. "
            "Use read tools (get_*/list_*) for lookups. "
            "All amounts should be strings (e.g., '100.00'). "
            "Currency codes: usd, eur, usdc, usdt, eurc. "
            "Networks: ach, wire, sepa (fiat); ethereum, polygon, sol, base, arbitrum, tron, avalanche, optimism (crypto)."
        ),
    )

    # Register resources and tools
    register_resources(mcp)
    register_workflow_tools(
        mcp,
        customer_svc,
        funding_svc,
        transfer_svc,
        business_rep_svc,
        virtual_account_svc,
        offloader_wallet_svc,
    )
    register_read_tools(mcp, gateway)

    logger.info("SpherePay MCP server ready with 24 tools and 5 resources")
    return mcp


def main() -> None:
    mcp = create_server()
    mcp.run()


if __name__ == "__main__":
    main()
