<?php

declare(strict_types=1);

namespace Kylin\Payment;

use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Request;
use Kylin\Payment\Services\PaymentRecordService;
use Kylin\Payment\Services\PaymentCallbackLogService;
use Kylin\Payment\Services\PaymentStatisticsService;
use Kylin\Payment\Services\LanguageService;
use Kylin\Payment\Services\ConfigCacheService;
use Kylin\Payment\Services\QueueService;
use Kylin\Payment\Services\PaymentScenarioService;
use Kylin\Payment\Services\SecurityService;
use Kylin\Payment\Services\VersionManagerService;
use Kylin\Payment\Services\TestToolService;
use Kylin\Payment\Services\NotificationService;
use Kylin\Payment\Services\QrCodeService;
use Kylin\Payment\Services\PaymentLinkService;
use Kylin\Payment\Services\ProfitSharingService;
use Kylin\Payment\Services\CouponService;
use Kylin\Payment\Services\ReportService;
use Kylin\Payment\Services\PaymentRetryService;
use Kylin\Payment\Services\PaymentTimeoutService;
use Kylin\Payment\Services\PaymentPreCreateService;
use Kylin\Payment\Services\PaymentDataMaskingService;
use Kylin\Payment\Services\PaymentRateLimitService;
use Kylin\Payment\Services\PaymentWebhookService;
use Kylin\Payment\Services\PaymentIntelligentRoutingService;
use Kylin\Payment\Services\PaymentBatchOperationService;
use Kylin\Payment\Services\PaymentRiskControlService;
use Kylin\Payment\Gateways\WechatGateway;
use Kylin\Payment\Gateways\AlipayGateway;
use Kylin\Payment\Gateways\UnionpayGateway;
use Kylin\Payment\Gateways\DouyinGateway;
use Kylin\Payment\Gateways\JsbankGateway;
use Kylin\Payment\Gateways\AlipayGlobalGateway;
use Kylin\Payment\Gateways\PaypalGateway;
use Kylin\Payment\Gateways\StripeGateway;
use Kylin\Payment\Gateways\GooglePayGateway;
use Kylin\Payment\Gateways\ApplePayGateway;

/**
 * 支付核心类
 *
 * 提供统一的支付接口，支持多种支付方式和支付场景
 *
 * @package Kylin\Payment
 */
final class Payment
{
    /**
     * 构造函数
     *
     * @param Container $app 应用容器实例
     * @param PaymentManager|null $manager 支付管理器实例
     * @param PaymentRecordService|null $paymentRecordService 支付记录服务
     * @param PaymentCallbackLogService|null $callbackLogService 回调日志服务
     * @param PaymentStatisticsService|null $paymentStatisticsService 支付统计服务
     * @param LanguageService|null $languageService 语言服务
     * @param ConfigCacheService|null $configCacheService 配置缓存服务
     * @param QueueService|null $queueService 队列服务
     * @param PaymentScenarioService|null $scenarioService 支付场景服务
     * @param SecurityService|null $securityService 安全服务
     * @param VersionManagerService|null $versionManagerService 版本管理服务
     * @param TestToolService|null $testToolService 测试工具服务
     * @param NotificationService|null $notificationService 通知服务
     * @param QrCodeService|null $qrCodeService 二维码服务
     * @param PaymentLinkService|null $paymentLinkService 支付链接服务
     * @param ProfitSharingService|null $profitSharingService 分账服务
     * @param CouponService|null $couponService 优惠券服务
     * @param ReportService|null $reportService 报表服务
     * @param PaymentRetryService|null $paymentRetryService 支付重试服务
     * @param PaymentTimeoutService|null $paymentTimeoutService 支付超时服务
     * @param PaymentPreCreateService|null $paymentPreCreateService 支付预创建服务
     * @param PaymentDataMaskingService|null $paymentDataMaskingService 数据脱敏服务
     * @param PaymentRateLimitService|null $paymentRateLimitService 限流服务
     * @param PaymentWebhookService|null $paymentWebhookService Webhook服务
     * @param PaymentIntelligentRoutingService|null $paymentIntelligentRoutingService 智能路由服务
     * @param PaymentBatchOperationService|null $paymentBatchOperationService 批量操作服务
     * @param PaymentRiskControlService|null $paymentRiskControlService 风控服务
     */
    public function __construct(
        private readonly Container $app,
        private readonly ?PaymentManager $manager = null,
        private readonly ?PaymentRecordService $paymentRecordService = null,
        private readonly ?PaymentCallbackLogService $callbackLogService = null,
        private readonly ?PaymentStatisticsService $paymentStatisticsService = null,
        private readonly ?LanguageService $languageService = null,
        private readonly ?ConfigCacheService $configCacheService = null,
        private readonly ?QueueService $queueService = null,
        private readonly ?PaymentScenarioService $scenarioService = null,
        private readonly ?SecurityService $securityService = null,
        private readonly ?VersionManagerService $versionManagerService = null,
        private readonly ?TestToolService $testToolService = null,
        private readonly ?NotificationService $notificationService = null,
        private readonly ?QrCodeService $qrCodeService = null,
        private readonly ?PaymentLinkService $paymentLinkService = null,
        private readonly ?ProfitSharingService $profitSharingService = null,
        private readonly ?CouponService $couponService = null,
        private readonly ?ReportService $reportService = null,
        private readonly ?PaymentRetryService $paymentRetryService = null,
        private readonly ?PaymentTimeoutService $paymentTimeoutService = null,
        private readonly ?PaymentPreCreateService $paymentPreCreateService = null,
        private readonly ?PaymentDataMaskingService $paymentDataMaskingService = null,
        private readonly ?PaymentRateLimitService $paymentRateLimitService = null,
        private readonly ?PaymentWebhookService $paymentWebhookService = null,
        private readonly ?PaymentIntelligentRoutingService $paymentIntelligentRoutingService = null,
        private readonly ?PaymentBatchOperationService $paymentBatchOperationService = null,
        private readonly ?PaymentRiskControlService $paymentRiskControlService = null
    ) {
    }

    /**
     * 获取支付管理器
     *
     * @return PaymentManager 支付管理器实例
     */
    public function manager(): PaymentManager
    {
        return $this->manager ??= new PaymentManager($this->app);
    }

    /**
     * 获取支付记录服务
     *
     * @return PaymentRecordService 支付记录服务实例
     */
    public function paymentRecord(): PaymentRecordService
    {
        return $this->paymentRecordService ??= new PaymentRecordService($this->app);
    }

    /**
     * 获取回调日志服务
     *
     * @return PaymentCallbackLogService 回调日志服务实例
     */
    public function callbackLog(): PaymentCallbackLogService
    {
        return $this->callbackLogService ??= new PaymentCallbackLogService($this->app);
    }

    /**
     * 获取支付统计服务
     *
     * @return PaymentStatisticsService 支付统计服务实例
     */
    public function statistics(): PaymentStatisticsService
    {
        return $this->paymentStatisticsService ??= new PaymentStatisticsService($this->app);
    }

    /**
     * 获取语言服务
     *
     * @return LanguageService 语言服务实例
     */
    public function lang(): LanguageService
    {
        return $this->languageService ??= new LanguageService($this->app);
    }

    /**
     * 获取配置缓存服务
     *
     * @return ConfigCacheService 配置缓存服务实例
     */
    public function configCache(): ConfigCacheService
    {
        return $this->configCacheService ??= new ConfigCacheService($this->app);
    }

    /**
     * 获取队列服务
     *
     * @return QueueService 队列服务实例
     */
    public function queue(): QueueService
    {
        return $this->queueService ??= new QueueService($this->app);
    }

    /**
     * 获取支付场景服务
     *
     * @return PaymentScenarioService 支付场景服务实例
     */
    public function scenario(): PaymentScenarioService
    {
        return $this->scenarioService ??= new PaymentScenarioService($this->app);
    }

    /**
     * 获取安全服务
     *
     * @return SecurityService 安全服务实例
     */
    public function security(): SecurityService
    {
        return $this->securityService ??= new SecurityService($this->app);
    }

    /**
     * 获取版本管理服务
     *
     * @return VersionManagerService 版本管理服务实例
     */
    public function version(): VersionManagerService
    {
        return $this->versionManagerService ??= new VersionManagerService($this->app);
    }

    /**
     * 获取测试工具服务
     *
     * @return TestToolService 测试工具服务实例
     */
    public function test(): TestToolService
    {
        return $this->testToolService ??= new TestToolService($this->app);
    }

    /**
     * 获取通知服务
     *
     * @return NotificationService 通知服务实例
     */
    public function notify(): NotificationService
    {
        return $this->notificationService ??= new NotificationService($this->app);
    }

    /**
     * 获取二维码服务
     *
     * @return QrCodeService 二维码服务实例
     */
    public function qrcode(): QrCodeService
    {
        return $this->qrCodeService ??= new QrCodeService($this->app);
    }

    /**
     * 获取支付链接服务
     *
     * @return PaymentLinkService 支付链接服务实例
     */
    public function link(): PaymentLinkService
    {
        return $this->paymentLinkService ??= new PaymentLinkService($this->app);
    }

    /**
     * 获取分账服务
     *
     * @return ProfitSharingService 分账服务实例
     */
    public function sharing(): ProfitSharingService
    {
        return $this->profitSharingService ??= new ProfitSharingService($this->app);
    }

    /**
     * 获取优惠券服务
     *
     * @return CouponService 优惠券服务实例
     */
    public function coupon(): CouponService
    {
        return $this->couponService ??= new CouponService($this->app);
    }

    /**
     * 获取报表服务
     *
     * @return ReportService 报表服务实例
     */
    public function report(): ReportService
    {
        return $this->reportService ??= new ReportService($this->app);
    }

    /**
     * 获取支付重试服务
     *
     * @return PaymentRetryService 支付重试服务实例
     */
    public function retry(): PaymentRetryService
    {
        return $this->paymentRetryService ??= new PaymentRetryService($this->app);
    }

    /**
     * 获取支付超时处理服务
     *
     * @return PaymentTimeoutService 支付超时服务实例
     */
    public function timeout(): PaymentTimeoutService
    {
        return $this->paymentTimeoutService ??= new PaymentTimeoutService($this->app);
    }

    /**
     * 获取支付预创建服务
     *
     * @return PaymentPreCreateService 支付预创建服务实例
     */
    public function preCreate(): PaymentPreCreateService
    {
        return $this->paymentPreCreateService ??= new PaymentPreCreateService($this->app);
    }

    /**
     * 获取支付数据脱敏服务
     *
     * @return PaymentDataMaskingService 数据脱敏服务实例
     */
    public function masking(): PaymentDataMaskingService
    {
        return $this->paymentDataMaskingService ??= new PaymentDataMaskingService($this->app);
    }

    /**
     * 获取支付接口限流服务
     *
     * @return PaymentRateLimitService 限流服务实例
     */
    public function rateLimit(): PaymentRateLimitService
    {
        return $this->paymentRateLimitService ??= new PaymentRateLimitService($this->app);
    }

    /**
     * 获取支付Webhook服务
     *
     * @return PaymentWebhookService Webhook服务实例
     */
    public function webhook(): PaymentWebhookService
    {
        return $this->paymentWebhookService ??= new PaymentWebhookService($this->app);
    }

    /**
     * 获取支付智能路由服务
     *
     * @return PaymentIntelligentRoutingService 智能路由服务实例
     */
    public function routing(): PaymentIntelligentRoutingService
    {
        return $this->paymentIntelligentRoutingService ??= new PaymentIntelligentRoutingService($this->app);
    }

    /**
     * 获取支付批量操作服务
     *
     * @return PaymentBatchOperationService 批量操作服务实例
     */
    public function batch(): PaymentBatchOperationService
    {
        return $this->paymentBatchOperationService ??= new PaymentBatchOperationService($this->app);
    }

    /**
     * 获取支付风控服务
     *
     * @return PaymentRiskControlService 风控服务实例
     */
    public function risk(): PaymentRiskControlService
    {
        return $this->paymentRiskControlService ??= new PaymentRiskControlService($this->app);
    }

    /**
     * 获取微信支付实例
     *
     * @param string $name 配置名称
     * @return WechatGateway 微信支付网关实例
     */
    public function wechat(string $name = 'default'): WechatGateway
    {
        return $this->manager()->wechat($name);
    }

    /**
     * 获取支付宝支付实例
     *
     * @param string $name 配置名称
     * @return AlipayGateway 支付宝支付网关实例
     */
    public function alipay(string $name = 'default'): AlipayGateway
    {
        return $this->manager()->alipay($name);
    }

    /**
     * 获取银联支付实例
     *
     * @param string $name 配置名称
     * @return UnionpayGateway 银联支付网关实例
     */
    public function unionpay(string $name = 'default'): UnionpayGateway
    {
        return $this->manager()->unionpay($name);
    }

    /**
     * 获取抖音支付实例
     *
     * @param string $name 配置名称
     * @return DouyinGateway 抖音支付网关实例
     */
    public function douyin(string $name = 'default'): DouyinGateway
    {
        return $this->manager()->douyin($name);
    }

    /**
     * 获取江苏银行支付实例
     *
     * @param string $name 配置名称
     * @return JsbankGateway 江苏银行支付网关实例
     */
    public function jsbank(string $name = 'default'): JsbankGateway
    {
        return $this->manager()->jsbank($name);
    }

    /**
     * 获取支付宝国际版实例
     *
     * @param string $name 配置名称
     * @return AlipayGlobalGateway 支付宝国际版网关实例
     */
    public function alipayGlobal(string $name = 'default'): AlipayGlobalGateway
    {
        return $this->manager()->alipayGlobal($name);
    }

    /**
     * 获取PayPal实例
     *
     * @param string $name 配置名称
     * @return PaypalGateway PayPal网关实例
     */
    public function paypal(string $name = 'default'): PaypalGateway
    {
        return $this->manager()->paypal($name);
    }

    /**
     * 获取Stripe实例
     *
     * @param string $name 配置名称
     * @return StripeGateway Stripe网关实例
     */
    public function stripe(string $name = 'default'): StripeGateway
    {
        return $this->manager()->stripe($name);
    }

    /**
     * 获取Google Pay实例
     *
     * @param string $name 配置名称
     * @return GooglePayGateway Google Pay网关实例
     */
    public function googlePay(string $name = 'default'): GooglePayGateway
    {
        return $this->manager()->googlePay($name);
    }

    /**
     * 获取Apple Pay实例
     *
     * @param string $name 配置名称
     * @return ApplePayGateway Apple Pay网关实例
     */
    public function applePay(string $name = 'default'): ApplePayGateway
    {
        return $this->manager()->applePay($name);
    }

    /**
     * 统一支付方法
     *
     * @param string $type 支付类型
     * @param array $params 支付参数
     * @param string $name 配置名称
     * @return mixed 支付结果
     * @throws \Exception 如果支付失败
     */
    public function pay(string $type, array $params, string $name = 'default'): mixed
    {
        $this->log($type, 'pay', $params, '开始支付');

        try {
            $record = $this->paymentRecord()->create([
                'payment_type' => $type,
                'out_trade_no' => $params['out_trade_no'] ?? '',
                'amount' => $params['total_amount'] ?? $params['amount'] ?? $params['total_fee'] ?? 0,
                'currency' => $params['currency'] ?? 'CNY',
                'payload' => $params,
            ]);

            $gateway = $this->manager()->gateway($type, $name);
            $result = $gateway->pay($params);

            $this->paymentRecord()->updateResult($record->id, $result);

            $this->log($type, 'pay', $params, '支付成功', $result);
            return $result;
        } catch (\Exception $e) {
            $this->log($type, 'pay', $params, "支付失败: {$e->getMessage()}");
            throw $e;
        }
    }

    /**
     * 统一查询方法
     *
     * @param string $type 支付类型
     * @param string $orderNo 订单号
     * @param string $name 配置名称
     * @return mixed 查询结果
     * @throws \Exception 如果查询失败
     */
    public function query(string $type, string $orderNo, string $name = 'default'): mixed
    {
        $this->log($type, 'query', ['order_no' => $orderNo], '开始查询订单');

        try {
            $gateway = $this->manager()->gateway($type, $name);
            $result = $gateway->query($orderNo);

            $this->log($type, 'query', ['order_no' => $orderNo], '订单查询成功', $result);
            return $result;
        } catch (\Exception $e) {
            $this->log($type, 'query', ['order_no' => $orderNo], "订单查询失败: {$e->getMessage()}");
            throw $e;
        }
    }

    /**
     * 统一退款方法
     *
     * @param string $type 支付类型
     * @param array $params 退款参数
     * @param string $name 配置名称
     * @return mixed 退款结果
     * @throws \Exception 如果退款失败
     */
    public function refund(string $type, array $params, string $name = 'default'): mixed
    {
        $this->log($type, 'refund', $params, '开始退款');

        try {
            $gateway = $this->manager()->gateway($type, $name);
            $result = $gateway->refund($params);

            $record = $this->paymentRecord()->getByOutTradeNo($params['out_trade_no'] ?? '', $type);
            if ($record) {
                $this->paymentRecord()->markAsRefunded($record->id, [
                    'remark' => $params['refund_reason'] ?? '',
                ]);
            }

            $this->log($type, 'refund', $params, '退款成功', $result);
            return $result;
        } catch (\Exception $e) {
            $this->log($type, 'refund', $params, "退款失败: {$e->getMessage()}");
            throw $e;
        }
    }

    /**
     * 统一关闭方法
     *
     * @param string $type 支付类型
     * @param string $orderNo 订单号
     * @param string $name 配置名称
     * @return mixed 关闭结果
     * @throws \Exception 如果关闭失败
     */
    public function close(string $type, string $orderNo, string $name = 'default'): mixed
    {
        $this->log($type, 'close', ['order_no' => $orderNo], '开始关闭订单');

        try {
            $gateway = $this->manager()->gateway($type, $name);
            $result = $gateway->close($orderNo);

            $record = $this->paymentRecord()->getByOutTradeNo($orderNo, $type);
            if ($record) {
                $this->paymentRecord()->markAsClosed($record->id, '主动关闭');
            }

            $this->log($type, 'close', ['order_no' => $orderNo], '订单关闭成功', $result);
            return $result;
        } catch (\Exception $e) {
            $this->log($type, 'close', ['order_no' => $orderNo], "订单关闭失败: {$e->getMessage()}");
            throw $e;
        }
    }

    /**
     * 统一回调处理方法
     *
     * @param string $type 支付类型
     * @param array $data 回调数据
     * @param string $name 配置名称
     * @param Request|null $request 请求对象
     * @return mixed 回调处理结果
     * @throws \Exception 如果回调处理失败
     */
    public function callback(string $type, array $data, string $name = 'default', ?Request $request = null): mixed
    {
        $this->log($type, 'callback', $data, '开始处理回调');

        try {
            $log = null;
            if ($request) {
                $outTradeNo = $data['out_trade_no'] ?? $data['out_trade_no_'] ?? '';
                $tradeNo = $data['trade_no'] ?? $data['transaction_id'] ?? '';
                $log = $this->callbackLog()->createFromRequest($request, $type, $outTradeNo, $tradeNo);
            }

            $gateway = $this->manager()->gateway($type, $name);
            $result = $gateway->callback($data);

            if ($log) {
                $this->callbackLog()->markAsSuccess($log->id, $result);
            }

            $outTradeNo = $data['out_trade_no'] ?? $data['out_trade_no_'] ?? '';
            if ($outTradeNo) {
                $record = $this->paymentRecord()->getByOutTradeNo($outTradeNo, $type);
                if ($record) {
                    $this->paymentRecord()->markAsSuccess($record->id, [
                        'trade_no' => $data['trade_no'] ?? $data['transaction_id'] ?? '',
                        'callback_data' => $data,
                    ]);
                }
            }

            $this->log($type, 'callback', $data, '回调处理成功', $result);
            return $result;
        } catch (\Exception $e) {
            if ($log) {
                $this->callbackLog()->markAsFailed($log->id, $e->getMessage());
            }

            $this->log($type, 'callback', $data, "回调处理失败: {$e->getMessage()}");
            throw $e;
        }
    }

    /**
     * 记录支付日志
     *
     * @param string $type 支付类型
     * @param string $action 操作类型
     * @param array $data 操作数据
     * @param string $message 日志消息
     * @param mixed $result 操作结果
     * @return void
     */
    public function log(string $type, string $action, array $data = [], string $message = '', mixed $result = null): void
    {
        $logData = [
            'type' => $type,
            'action' => $action,
            'data' => $data,
            'message' => $message,
            'result' => $result,
            'timestamp' => date('Y-m-d H:i:s'),
        ];

        Log::channel('payment')->info('支付日志', $logData);
    }

    /**
     * 动态调用
     *
     * @param string $method 方法名
     * @param array $parameters 方法参数
     * @return mixed 调用结果
     * @throws \BadMethodCallException 如果方法不存在
     */
    public function __call(string $method, array $parameters): mixed
    {
        if (method_exists($this, $method)) {
            return $this->{$method}(...$parameters);
        }

        if (method_exists($this->manager(), $method)) {
            return $this->manager()->{$method}(...$parameters);
        }

        throw new \BadMethodCallException(sprintf('方法不存在: %s', $method));
    }
}
