<?php

declare(strict_types=1);


namespace App\Blog\Services;

use App\Blog\Support\PluginManager;
use App\Blog\Support\ThemeManager;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use ZipArchive;

class PackageInstaller
{
    /**
     * 从 ZIP 安装插件或主题。
     *
     * @return array{type: string, key: string}
     */
    public function installZip(string $zipPath): array
    {
        $zip = new ZipArchive;

        if ($zip->open($zipPath) !== true) {
            throw new \InvalidArgumentException('无法打开 ZIP 文件');
        }

        // 解析 manifest，校验包类型
        $manifest = $this->readManifestFromZip($zip);
        $type = $manifest['type'] ?? 'plugin';
        $name = $manifest['name'] ?? null;

        if (! in_array($type, ['plugin', 'theme'], true)) {
            throw new \InvalidArgumentException('未知的包类型：'.$type);
        }

        if ($type === 'plugin') {
            [$vendor, $pluginName] = array_pad(explode('.', (string) $name), 2, $name);
            $target = config('plugins.path').'/'.$vendor.'.'.$pluginName;
        } else {
            $target = config('themes.path').'/'.$name;
        }

        if (is_dir($target)) {
            throw new \InvalidArgumentException("目标已存在：{$target}");
        }

        File::ensureDirectoryExists(dirname($target));

        $tmp = storage_path('app/tmp/install-'.Str::random(8));
        File::ensureDirectoryExists($tmp);
        $zip->extractTo($tmp);
        $zip->close();

        // 兼容 ZIP 内嵌套一层目录
        $source = $tmp;
        if (count(File::directories($tmp)) === 1 && ! File::exists($tmp.'/plugin.json') && ! File::exists($tmp.'/theme.json')) {
            $source = File::directories($tmp)[0];
        }

        $manifestFile = $type === 'plugin' ? 'plugin.json' : 'theme.json';
        if (! File::exists($source.'/'.$manifestFile)) {
            File::deleteDirectory($tmp);
            throw new \InvalidArgumentException("包缺少 {$manifestFile}");
        }

        File::copyDirectory($source, $target);
        File::deleteDirectory($tmp);

        if ($type === 'plugin') {
            $this->installPluginFiles($vendor.'.'.$pluginName);
        } else {
            $this->publishThemeAssets($name);
        }

        return ['type' => $type, 'key' => $type === 'plugin' ? $vendor.'.'.$pluginName : $name];
    }

    /**
     * 从远程市场安装（带 checksum 校验）。
     */
    public function installFromMarket(array $item): array
    {
        if (empty($item['download_url'])) {
            throw new \InvalidArgumentException('缺少下载地址');
        }

        $client = app(MarketplaceClient::class);
        $zipPath = $client->download($item['download_url']);

        try {
            return $this->installZip($zipPath);
        } finally {
            File::delete($zipPath);
        }
    }

    private function readManifestFromZip(ZipArchive $zip): array
    {
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $entry = $zip->getNameIndex($i);
            $base = basename($entry);

            if ($base === 'plugin.json' || $base === 'theme.json') {
                $content = $zip->getFromIndex($i);
                $manifest = json_decode($content, true);

                if (! $manifest) {
                    throw new \InvalidArgumentException('manifest 解析失败');
                }

                $manifest['type'] = $base === 'plugin.json' ? 'plugin' : 'theme';

                return $manifest;
            }
        }

        throw new \InvalidArgumentException('ZIP 中未找到 manifest');
    }

    private function installPluginFiles(string $key): void
    {
        $manager = app(PluginManager::class);
        $provider = $manager->resolveProvider($key);

        // 运行插件迁移
        $migrations = $manager->path($key).'/database/migrations';
        if (is_dir($migrations) && $provider && class_exists($provider)) {
            Artisan::call('migrate', ['--path' => 'plugins/'.str_replace('.', '/', $key).'/database/migrations', '--force' => true]);
        }
    }

    private function publishThemeAssets(string $name): void
    {
        $manager = app(ThemeManager::class);
        $target = public_path('themes/'.$name);

        if (is_dir($manager->path($name).'/assets')) {
            File::copyDirectory($manager->path($name).'/assets', $target);
        }
    }

    /**
     * 卸载插件（删除目录 + 记录）。
     */
    public function uninstallPlugin(string $key): void
    {
        $manager = app(PluginManager::class);

        if (! $manager->exists($key)) {
            throw new \InvalidArgumentException('插件不存在');
        }

        // 内置插件不卸载（防止误删系统文件）
        if (in_array($key, config('plugins.enabled', []), true)) {
            throw new \InvalidArgumentException('内置插件不可卸载，只能停用');
        }

        $manager->uninstall($key);
        File::deleteDirectory($manager->path($key));
    }

    public function uninstallTheme(string $name): void
    {
        $manager = app(ThemeManager::class);

        if ($manager->active() === $name) {
            throw new \InvalidArgumentException('不能删除当前激活的主题');
        }

        if (! $manager->exists($name)) {
            throw new \InvalidArgumentException('主题不存在');
        }

        File::deleteDirectory($manager->path($name));
        File::deleteDirectory(public_path('themes/'.$name));
    }
}
