<?php

namespace Kylin\Admin;

use Composer\InstalledVersions;
use Illuminate\Foundation\Console\AboutCommand;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Kylin\Admin\Contracts\ExceptionHandler;
use Kylin\Admin\Exception\Handler;
use Kylin\Admin\Extend\Manager;
use Kylin\Admin\Extend\UpdateManager;
use Kylin\Admin\Extend\VersionManager;
use Kylin\Admin\Layout\Asset;
use Kylin\Admin\Layout\Content;
use Kylin\Admin\Layout\Menu;
use Kylin\Admin\Layout\Navbar;
use Kylin\Admin\Layout\SectionManager;
use Kylin\Admin\Support\Context;
use Kylin\Admin\Support\Helper;
use Kylin\Admin\Support\Setting;
use Kylin\Admin\Support\Translator;
use Kylin\Admin\Support\WebUploader;
use ReflectionClass;
use URL;

class AdminServiceProvider extends ServiceProvider
{
    /**
     * @var array
     */
    protected array $commands = [
        Console\AdminCommand::class,
        Console\InstallCommand::class,
        Console\PublishCommand::class,
        Console\UninstallCommand::class,
        Console\CreateUserCommand::class,
        Console\ResetPasswordCommand::class,
        Console\ExportSeedCommand::class,
        Console\IdeHelperCommand::class,
        Console\FormCommand::class,
        Console\ActionCommand::class,
        Console\MenuCacheCommand::class,
        Console\MinifyCommand::class,
        Console\AppCommand::class,
        Console\ExtensionMakeCommand::class,
        Console\ExtensionInstallCommand::class,
        Console\ExtensionUninstallCommand::class,
        Console\ExtensionRefreshCommand::class,
        Console\ExtensionRollbackCommand::class,
        Console\ExtensionEnableCommand::class,
        Console\ExtensionDiableCommand::class,
        Console\ExtensionUpdateCommand::class,
        Console\UpdateCommand::class,
    ];

    /**
     * 开发环境命令.
     *
     * @var array
     */
    protected array $devCommands = [
        Console\Development\LinkCommand::class,
    ];

    /**
     * @var array
     */
    protected array $routeMiddleware = [
        'admin.auth' => Http\Middleware\Authenticate::class,
        'admin.pjax' => Http\Middleware\Pjax::class,
        'admin.permission' => Http\Middleware\Permission::class,
        'admin.bootstrap' => Http\Middleware\Bootstrap::class,
        'admin.session' => Http\Middleware\Session::class,
        'admin.upload' => Http\Middleware\WebUploader::class,
        'admin.app' => Http\Middleware\Application::class,
    ];

    /**
     * @var array
     */
    protected array $middlewareGroups = [
        'admin' => [
            'admin.auth',
            'admin.pjax',
            'admin.bootstrap',
            'admin.permission',
            'admin.session',
            'admin.upload',
        ],
    ];

    public function boot(): void
    {
        AboutCommand::add('Kylin', [
            'Admin Version' => fn() => InstalledVersions::getPrettyVersion('kylin/admin'),
        ]);
        $this->registerDefaultSections();
        $this->registerViews();
        $this->ensureHttps();
        $this->bootApplication();
        $this->registerPublishing();
        $this->compatibleBlade();
        $this->bootExtensions();
        $this->registerBladeDirective();
    }

    /**
     * 默认 section 注册.
     */
    protected function registerDefaultSections(): void
    {
        Content::composing(function () {
            if (!admin_has_default_section(Admin::SECTION['NAVBAR_USER_PANEL'])) {
                admin_inject_default_section(Admin::SECTION['NAVBAR_USER_PANEL'], function () {
                    return view('admin::partials.navbar-user-panel', ['user' => Admin::user()]);
                });
            }

            if (!admin_has_default_section(Admin::SECTION['LEFT_SIDEBAR_USER_PANEL'])) {
                admin_inject_default_section(Admin::SECTION['LEFT_SIDEBAR_USER_PANEL'], function () {
                    return view('admin::partials.sidebar-user-panel', ['user' => Admin::user()]);
                });
            }

            // Register menu
            Admin::menu()->register();
        }, true);
    }

    public function register(): void
    {
        $this->aliasAdmin();
        $this->loadAdminAuthConfig();
        $this->registerRouteMiddleware();
        $this->registerServices();
        $this->registerExtensions();

        $this->commands($this->commands);

        if (config('app.debug')) {
            $this->commands($this->devCommands);
        }
    }

    protected function aliasAdmin(): void
    {
        if (!class_exists(\Admin::class)) {
            class_alias(Admin::class, \Admin::class);
        }
    }

    /**
     * 设置 auth 配置.
     *
     * @return void
     */
    protected function loadAdminAuthConfig(): void
    {
        config(Arr::dot(config('admin.auth', []), 'auth.'));

        foreach ((array)config('admin.multi_app') as $app => $enable) {
            if ($enable) {
                config(Arr::dot(config($app . '.auth', []), 'auth.'));
            }
        }
    }

    /**
     * 路由中间件注册.
     *
     * @return void
     */
    protected function registerRouteMiddleware(): void
    {
        $router = $this->app->make('router');

        // register route middleware.
        foreach ($this->routeMiddleware as $key => $middleware) {
            $router->aliasMiddleware($key, $middleware);
        }

        $disablePermission = !config('admin.permission.enable');

        // register middleware group.
        foreach ($this->middlewareGroups as $key => $middleware) {
            if ($disablePermission) {
                Helper::deleteByValue($middleware, 'admin.permission', true);
            }
            $router->middlewareGroup($key, $middleware);
        }
    }

    public function registerServices(): void
    {
        $this->app->singleton('admin.app', Application::class);
        $this->app->singleton('admin.asset', Asset::class);
        $this->app->singleton('admin.color', Color::class);
        $this->app->singleton('admin.sections', SectionManager::class);
        $this->app->singleton('admin.extend', Manager::class);
        $this->app->singleton('admin.extend.update', function () {
            return new UpdateManager(app('admin.extend'));
        });
        $this->app->singleton('admin.extend.version', function () {
            return new VersionManager(app('admin.extend'));
        });
        $this->app->singleton('admin.navbar', Navbar::class);
        $this->app->singleton('admin.menu', Menu::class);
        $this->app->singleton('admin.context', Context::class);
        $this->app->singleton('admin.setting', function () {
            return Setting::fromDatabase();
        });
        $this->app->singleton('admin.web-uploader', WebUploader::class);
        $this->app->singleton(ExceptionHandler::class, config('admin.exception_handler') ?: Handler::class);
        $this->app->singleton('admin.translator', Translator::class);
    }

    public function registerExtensions(): void
    {
        Admin::extension()->register();
    }

    protected function registerViews(): void
    {
        $this->loadViewsFrom(__DIR__ . '/../resources/views', 'admin');
    }

    /**
     * 是否强制使用https.
     *
     * @return void
     */
    protected function ensureHttps(): void
    {
        if (config('admin.https') || config('admin.secure')) {
            URL::forceScheme('https');
            $this->app['request']->server->set('HTTPS', true);
        }
    }

    /**
     * 路由注册.
     */
    protected function bootApplication(): void
    {
        Admin::app()->boot();
    }

    /**
     * 资源发布注册.
     *
     * @return void
     */
    protected function registerPublishing(): void
    {
        if ($this->app->runningInConsole()) {
            $this->publishes([__DIR__ . '/../config' => config_path()], 'kylin-admin-config');
            $this->publishes([__DIR__ . '/../resources/lang' => $this->app->langPath()], 'kylin-admin-lang');
            $this->publishes([__DIR__ . '/../database/migrations' => database_path('migrations')], 'kylin-admin-migrations');
            $this->publishes([__DIR__ . '/../resources/dist' => public_path(Admin::asset()->getRealPath('@admin'))], 'kylin-admin-assets');
        }
    }

    /**
     * 禁止laravel 5.6或更高版本中启用双编码的默认特性.
     *
     * @return void
     */
    protected function compatibleBlade(): void
    {
        $bladeReflectionClass = new ReflectionClass('\Illuminate\View\Compilers\BladeCompiler');
        if ($bladeReflectionClass->hasMethod('withoutDoubleEncoding')) {
            Blade::withoutDoubleEncoding();
        }
    }

    public function bootExtensions(): void
    {
        Admin::extension()->boot();
    }

    protected function registerBladeDirective(): void
    {
        Blade::directive('primary', function ($amt = 0) {
            return <<<PHP
<?php echo admin_color()->primary($amt); ?>
PHP;
        });
    }
}
