<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
namespace app\command;

use Core\service\module\CoreModuleService;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;


/**
 * Module Manager
 * @package app\command
 */
class ModuleManager extends Command
{
    /**
     * 配置模块管理命令参数和选项
     * @return void
     */
    protected function configure()
    {
        $this->setName('module')
            ->setDescription('')
            ->addArgument('action', Argument::REQUIRED, '')
            ->addArgument('module', Argument::OPTIONAL, '')
            ->addArgument('file', Argument::OPTIONAL, '')
            ->addOption('drop-tables', null, Option::VALUE_NONE, '')
            ->addOption('keep-tables', null, Option::VALUE_NONE, '')
            ->addOption('init', null, Option::VALUE_NONE, '');
    }


    /**
     * 执行模块管理命令
     * @param Input $input
     * @param Output $output
     * @return void
     */
    protected function execute(Input $input, Output $output)
    {
        $action = $input->getArgument('action');
        $module = $input->getArgument('module');
        $file = $input->getArgument('file');
        $dropTables = $input->getOption('drop-tables');
        $keepTables = $input->getOption('keep-tables');
        $init = $input->getOption('init');


        $shouldDropTables = $dropTables && !$keepTables;

        /** @var CoreModuleService $service */
        $service = $this->app->make(CoreModuleService::class);

        if ($init) {
            $registered = $service->initManifests();
            $output->info('' . implode(', ', $registered));
            return;
        }

        try {
            switch ($action) {
                case 'list':
                    $this->actionList($output, $service);
                    break;
                case 'status':
                    $this->actionStatus($output, $service, $module);
                    break;
                case 'backup':
                    $this->actionBackup($output, $service, $module);
                    break;
                case 'remove':
                    $this->actionRemove($output, $service, $module, $shouldDropTables);
                    break;
                case 'restore':
                    $this->actionRestore($output, $service, $file);
                    break;
                default:
                    $output->error("{$action}");
                    $output->info('');
            }
        } catch (\Throwable $e) {
            $output->error('' . $e->getMessage());
        }
    }

    /**
     * 列出所有模块
     * @param Output $output
     * @param CoreModuleService $service
     * @return void
     */
    private function actionList(Output $output, CoreModuleService $service): void
    {
        $modules = $service->getModules();
        if (empty($modules)) {
            $output->info('');
            return;
        }

        $output->info(sprintf("%-4s %-20s %-20s %-8s %-10s %s", 'ID', '', '', '', '', ''));
        $output->info(str_repeat('-', 90));

        foreach ($modules as $mod) {
            $status = $mod['status'] ? '' : '';
            $removable = $mod['is_removable'] ? '' : '';
            $output->writeln(sprintf(
                "%-4s %-20s %-20s %-8s %-10s %s",
                $mod['id'], $mod['code'], mb_substr($mod['name'], 0, 20), $mod['type'], $status, $removable
            ));
        }
    }

    /**
     * 显示模块状态
     * @param Output $output
     * @param CoreModuleService $service
     * @param string|null $module
     * @return void
     */
    private function actionStatus(Output $output, CoreModuleService $service, ?string $module): void
    {
        if (empty($module)) {
            $output->error('');
            return;
        }

        $manifest = $service->getManifest($module);
        if (!$manifest) {
            $output->error("{$module}");
            return;
        }

        $output->info("{$manifest['code']}");
        $output->info("{$manifest['name']}");
        $output->info("{$manifest['version']}");
        $output->info("{$manifest['type']}");
        $output->info('' . ($manifest['status'] ? '' : ''));
        $output->info('' . ($manifest['is_removable'] ? '' : ''));
        $output->info('' . count($manifest['files'] ?? []));
        $output->info('' . implode(', ', $manifest['tables'] ?? []));
        $output->info('' . implode(', ', $manifest['dependencies'] ?? []));
        $output->info("{$manifest['description']}");
    }

    /**
     * 备份模块
     * @param Output $output
     * @param CoreModuleService $service
     * @param string|null $module 模块编码
     * @return void
     */
    private function actionBackup(Output $output, CoreModuleService $service, ?string $module): void
    {
        if (empty($module)) {
            $output->error('');
            return;
        }

        $output->info("{$module}' ...");
        $zipFile = $service->backup($module);
        $output->info("{$zipFile}");
    }

    /**
     * 卸载并移除模块
     * @param Output $output
     * @param CoreModuleService $service
     * @param string|null $module 模块编码
     * @param bool $dropTables 是否同时删除数据表
     * @return void
     */
    private function actionRemove(Output $output, CoreModuleService $service, ?string $module, bool $dropTables): void
    {
        if (empty($module)) {
            $output->error('');
            return;
        }

        if ($dropTables) {
            $output->writeln("{$module}");
            $output->writeln('');
            $output->writeln('');
            $output->writeln('');
            $output->writeln('');
            $output->writeln('');
            $output->writeln("");
            $output->writeln('');
        } else {
            $output->writeln("{$module}");
            $output->writeln('');
            $output->writeln('');
            $output->writeln('');
            $output->writeln('');
            $output->writeln('');
            $output->writeln("");
            $output->writeln('');
        }

        $output->writeln("");
        $output->writeln('');

        $confirmed = trim((string)fgets(STDIN));
        if (strtolower($confirmed) !== 'yes') {
            $output->info('');
            return;
        }

        $output->info("{$module}' ...");
        $result = $service->remove($module, $dropTables);

        $output->info('');
        $output->info('');
        $output->info('' . count($result['files_removed']) . '');
        if ($dropTables) {
            $output->info('' . count($result['tables_dropped']) . '');
        } else {
            $output->info('' . ($result['tables_total'] ?? 0) . '');
        }
        $output->info('' . count($result['permissions_unregistered']) . '');
        $output->info('');
    }

    /**
     * 恢复模块
     * @param Output $output
     * @param CoreModuleService $service
     * @param string|null $file 备份文件路径
     * @return void
     */
    private function actionRestore(Output $output, CoreModuleService $service, ?string $file): void
    {
        if (empty($file)) {
            $output->error('');
            return;
        }

        $output->info("{$file}");
        $result = $service->restore($file);

        $output->info("{$result['module']}");
        $output->info('' . count($result['files_restored']) . '');
        $output->info('' . count($result['tables_restored']) . '');
        $output->info('' . count($result['permissions_registered']) . '');
    }
}