<?php

declare(strict_types=1);

namespace Kylin\Pay;

use Closure;
use Psr\Container\ContainerInterface;
use Kylin\Pay\Artful\Artful;
use Kylin\Pay\Artful\Event\ArtfulEnd;
use Kylin\Pay\Artful\Event\ArtfulStart;
use Kylin\Pay\Artful\Event\HttpEnd;
use Kylin\Pay\Artful\Event\HttpStart;
use Kylin\Pay\Artful\Exception\ContainerException;
use Kylin\Pay\Artful\Exception\ServiceNotFoundException;
use Kylin\Pay\Provider\Alipay;
use Kylin\Pay\Provider\Douyin;
use Kylin\Pay\Provider\Jsb;
use Kylin\Pay\Provider\Paypal;
use Kylin\Pay\Provider\Stripe;
use Kylin\Pay\Provider\Unipay;
use Kylin\Pay\Provider\Wechat;
use Kylin\Pay\Service\AlipayServiceProvider;
use Kylin\Pay\Service\DouyinServiceProvider;
use Kylin\Pay\Service\JsbServiceProvider;
use Kylin\Pay\Service\PaypalServiceProvider;
use Kylin\Pay\Service\StripeServiceProvider;
use Kylin\Pay\Service\UnipayServiceProvider;
use Kylin\Pay\Service\WechatServiceProvider;

/**
 * @method static Alipay alipay(array $config = [], $container = null)
 * @method static Wechat wechat(array $config = [], $container = null)
 * @method static Unipay unipay(array $config = [], $container = null)
 * @method static Jsb    jsb(array $config = [], $container = null)
 * @method static Douyin douyin(array $config = [], $container = null)
 * @method static Paypal paypal(array $config = [], $container = null)
 * @method static Stripe stripe(array $config = [], $container = null)
 */
class Pay
{
    /**
     * 正常模式.
     */
    public const MODE_NORMAL = 0;

    /**
     * 沙箱模式.
     */
    public const MODE_SANDBOX = 1;

    /**
     * 服务商模式.
     */
    public const MODE_SERVICE = 2;

    protected static array $providers = [
        AlipayServiceProvider::class,
        WechatServiceProvider::class,
        UnipayServiceProvider::class,
        JsbServiceProvider::class,
        DouyinServiceProvider::class,
        PaypalServiceProvider::class,
        StripeServiceProvider::class,
    ];

    /**
     * @throws ContainerException
     * @throws ServiceNotFoundException
     */
    public static function __callStatic(string $service, array $config = [])
    {
        if (!empty($config)) {
            self::config(...$config);
        }

        return Artful::get($service);
    }

    /**
     * @throws ContainerException
     */
    public static function config(array $config = [], Closure|ContainerInterface|null $container = null): bool
    {
        $result = Artful::config($config, $container);

        if ($result) {
            Event::addListener(ArtfulStart::class, [PayListener::class, 'artfulStart']);
            Event::addListener(ArtfulEnd::class, [PayListener::class, 'artfulEnd']);
            Event::addListener(HttpStart::class, [PayListener::class, 'httpStart']);
            Event::addListener(HttpEnd::class, [PayListener::class, 'httpEnd']);
        }

        foreach (self::$providers as $provider) {
            Artful::load($provider);
        }

        return $result;
    }

    /**
     * @throws ContainerException
     */
    public static function set(string $name, mixed $value): void
    {
        Artful::set($name, $value);
    }

    /**
     * @throws ContainerException
     * @throws ServiceNotFoundException
     */
    public static function get(string $service): mixed
    {
        return Artful::get($service);
    }

    public static function setContainer(Closure|ContainerInterface|null $container): void
    {
        Artful::setContainer($container);
    }

    public static function clear(): void
    {
        Artful::clear();
    }
}
