<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Blog\Support\PluginManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use RuntimeException;
use Tests\TestCase;

class PluginDependencyTest extends TestCase
{
    use RefreshDatabase;

    private function manager(): PluginManager
    {
        return app(PluginManager::class);
    }

    public function test_enable_plugin_with_disabled_dependency_throws(): void
    {
        $manager = $this->manager();

        // 先停用无依赖者的 membership，再停用 payment（此时无启用的依赖者）
        $manager->disable('neatstudio.membership');
        $manager->disable('neatstudio.payment');

        try {
            $manager->enable('neatstudio.membership');
            $this->fail('依赖未启用时应抛出异常');
        } catch (RuntimeException $e) {
            $this->assertStringContainsString('neatstudio.payment', $e->getMessage());
        }

        $this->assertFalse($manager->isEnabled('neatstudio.membership'));
    }

    public function test_disable_plugin_with_enabled_dependent_throws(): void
    {
        $manager = $this->manager();

        // 默认状态下 payment 已启用且 membership 依赖它
        try {
            $manager->disable('neatstudio.payment');
            $this->fail('存在已启用的依赖者时应抛出异常');
        } catch (RuntimeException $e) {
            $this->assertStringContainsString('neatstudio.membership', $e->getMessage());
        }

        $this->assertTrue($manager->isEnabled('neatstudio.payment'));
    }

    public function test_disable_plugin_without_dependents_works(): void
    {
        $manager = $this->manager();

        $manager->disable('neatstudio.membership');
        $this->assertFalse($manager->isEnabled('neatstudio.membership'));

        // 依赖（payment）仍启用，可重新启用
        $manager->enable('neatstudio.membership');
        $this->assertTrue($manager->isEnabled('neatstudio.membership'));
    }

    public function test_all_reports_dependency_status(): void
    {
        $manager = $this->manager();

        $plugins = $manager->all();
        $member = $plugins['neatstudio.membership'];

        $this->assertSame(['neatstudio.payment'], $member['requires']);
        $this->assertTrue($member['dependencies'][0]['ok']);
        $this->assertEmpty($member['dependency_errors']);
        $this->assertNotEmpty($member['usage']);

        // 停用依赖后，依赖状态应变为失败
        $manager->disable('neatstudio.membership');
        $manager->disable('neatstudio.payment');

        $plugins = $manager->all();
        $this->assertFalse($plugins['neatstudio.membership']['dependencies'][0]['ok']);
        $this->assertSame(['neatstudio.payment'], $plugins['neatstudio.membership']['dependency_errors']);
    }

    public function test_uninstall_plugin_with_enabled_dependent_throws(): void
    {
        $manager = $this->manager();

        try {
            $manager->uninstall('neatstudio.payment');
            $this->fail('存在已启用的依赖者时应抛出异常');
        } catch (RuntimeException $e) {
            $this->assertStringContainsString('neatstudio.membership', $e->getMessage());
        }

        // 卸载失败，记录仍在
        $this->assertTrue($manager->isEnabled('neatstudio.payment'));
    }

    public function test_dependency_problems_for_missing_plugin(): void
    {
        $manager = $this->manager();

        // 默认依赖完好
        $this->assertSame([], $manager->dependencyProblems('neatstudio.membership'));

        // 停用依赖后出现问题（先停用无依赖者的 membership）
        $manager->disable('neatstudio.membership');
        $manager->disable('neatstudio.payment');
        $this->assertNotEmpty($manager->dependencyProblems('neatstudio.membership'));

        // 不存在的插件没有依赖问题（空 requires）
        $this->assertSame([], $manager->dependencyProblems('neatstudio.does-not-exist'));
    }
}
