<?php

declare(strict_types=1);

namespace Kylin\Wechat\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Contracts\Container\Container;
use Kylin\Wechat\Wechat\WechatManager;
use Kylin\Wechat\Http\Middleware\OAuthAuthenticate;
use Kylin\Wechat\Services\WechatMessageService;
use Kylin\Wechat\Services\WechatUserService;
use Kylin\Wechat\Services\WechatMaterialService;
use Kylin\Wechat\Services\WechatMenuService;
use Kylin\Wechat\Services\WechatQrCodeService;
use Kylin\Wechat\Services\WechatCardService;
use Kylin\Wechat\Services\WechatCustomerService;
use Kylin\Wechat\Services\WechatMiniProgramService;
use Kylin\Wechat\Services\WechatWorkService;
use Kylin\Wechat\Services\WechatOpenPlatformService;
use Kylin\Wechat\Services\WechatPaymentService;
use Kylin\Wechat\Services\WechatShakeAroundService;
use Kylin\Wechat\Services\WechatTransferService;
use Kylin\Wechat\Services\WechatAdvertService;
use Kylin\Wechat\Services\WechatInvoiceService;
use Kylin\Wechat\Services\WechatSecurityService;
use Kylin\Wechat\Services\WechatDeviceService;
use Kylin\Wechat\Services\WechatPoiService;
use Kylin\Wechat\Services\WechatLiveService;
use Kylin\Wechat\Services\WechatSearchService;
use Kylin\Wechat\Services\WechatSubscriptionService;
use Kylin\Wechat\Services\WechatVideoAccountService;
use Kylin\Wechat\Services\WechatAiService;
use Kylin\Wechat\Services\WechatCloudService;
use Kylin\Wechat\Services\WechatTravelService;

final class WechatServiceProvider extends ServiceProvider implements DeferrableProvider
{
    private const SUPPORTED_SERVICES = [
        'official_account',
        'mini_program',
        'open_platform',
        'work',
        'open_work',
        'payment',
    ];

    public function register(): void
    {
        $this->mergeConfigFrom(
            __DIR__ . '/../../config/wechat.php',
            'wechat'
        );

        $this->app->singleton('wechat', fn (Container $app): WechatManager => new WechatManager($app));
        $this->app->singleton('wechat.factory', fn (Container $app): WechatManager => $app['wechat']);
        $this->app->singleton('wechat.message', fn (Container $app): WechatMessageService => new WechatMessageService($app));
        $this->app->singleton('wechat.user', fn (Container $app): WechatUserService => new WechatUserService($app));
        $this->app->singleton('wechat.material', fn (Container $app): WechatMaterialService => new WechatMaterialService($app));
        $this->app->singleton('wechat.menu', fn (Container $app): WechatMenuService => new WechatMenuService($app));
        $this->app->singleton('wechat.qrcode', fn (Container $app): WechatQrCodeService => new WechatQrCodeService($app));
        $this->app->singleton('wechat.card', fn (Container $app): WechatCardService => new WechatCardService($app));
        $this->app->singleton('wechat.customer', fn (Container $app): WechatCustomerService => new WechatCustomerService($app));
        $this->app->singleton('wechat.miniprogram', fn (Container $app): WechatMiniProgramService => new WechatMiniProgramService($app));
        $this->app->singleton('wechat.work', fn (Container $app): WechatWorkService => new WechatWorkService($app));
        $this->app->singleton('wechat.open_platform', fn (Container $app): WechatOpenPlatformService => new WechatOpenPlatformService($app));
        $this->app->singleton('wechat.payment', fn (Container $app): WechatPaymentService => new WechatPaymentService($app));
        $this->app->singleton('wechat.shake_around', fn (Container $app): WechatShakeAroundService => new WechatShakeAroundService($app));
        $this->app->singleton('wechat.transfer', fn (Container $app): WechatTransferService => new WechatTransferService($app));
        $this->app->singleton('wechat.advert', fn (Container $app): WechatAdvertService => new WechatAdvertService($app));
        $this->app->singleton('wechat.invoice', fn (Container $app): WechatInvoiceService => new WechatInvoiceService($app));
        $this->app->singleton('wechat.security', fn (Container $app): WechatSecurityService => new WechatSecurityService($app));
        $this->app->singleton('wechat.device', fn (Container $app): WechatDeviceService => new WechatDeviceService($app));
        $this->app->singleton('wechat.poi', fn (Container $app): WechatPoiService => new WechatPoiService($app));
        $this->app->singleton('wechat.live', fn (Container $app): WechatLiveService => new WechatLiveService($app));
        $this->app->singleton('wechat.search', fn (Container $app): WechatSearchService => new WechatSearchService($app));
        $this->app->singleton('wechat.subscription', fn (Container $app): WechatSubscriptionService => new WechatSubscriptionService($app));
        $this->app->singleton('wechat.video_account', fn (Container $app): WechatVideoAccountService => new WechatVideoAccountService($app));
        $this->app->singleton('wechat.ai', fn (Container $app): WechatAiService => new WechatAiService($app));
        $this->app->singleton('wechat.cloud', fn (Container $app): WechatCloudService => new WechatCloudService($app));
        $this->app->singleton('wechat.travel', fn (Container $app): WechatTravelService => new WechatTravelService($app));

        $this->registerServices();
    }

    protected function registerServices(): void
    {
        foreach (self::SUPPORTED_SERVICES as $service) {
            $this->app->singleton(
                "easywechat.{$service}",
                fn (Container $app): mixed => $app['wechat']->driver($service)
            );

            $this->app->singleton(
                "easywechat.{$service}.factory",
                fn (Container $app) => fn (string $name = 'default'): mixed => $app['wechat']->driver($service, $name)
            );
        }
    }

    public function boot(): void
    {
        $this->publishes([
            __DIR__ . '/../../config/wechat.php' => config_path('wechat.php'),
        ], 'wechat-config');

        $this->registerMiddleware();
    }

    protected function registerMiddleware(): void
    {
        $this->app['router']->aliasMiddleware('easywechat.oauth', OAuthAuthenticate::class);
    }

    public function provides(): array
    {
        $provides = [
            'wechat',
            'wechat.factory',
            'wechat.message',
            'wechat.user',
            'wechat.material',
            'wechat.menu',
            'wechat.qrcode',
            'wechat.card',
            'wechat.customer',
            'wechat.miniprogram',
            'wechat.work',
            'wechat.open_platform',
            'wechat.payment',
            'wechat.shake_around',
            'wechat.transfer',
            'wechat.advert',
            'wechat.invoice',
            'wechat.security',
            'wechat.device',
            'wechat.poi',
            'wechat.live',
            'wechat.search',
            'wechat.subscription',
            'wechat.video_account',
            'wechat.ai',
            'wechat.cloud',
            'wechat.travel'
        ];

        foreach (self::SUPPORTED_SERVICES as $service) {
            $provides[] = "easywechat.{$service}";
            $provides[] = "easywechat.{$service}.factory";
        }

        return $provides;
    }

    public static function getSupportedServices(): array
    {
        return self::SUPPORTED_SERVICES;
    }
}
