<?php

namespace Kylin\Modules;

use Illuminate\Container\Container;
use Kylin\Modules\Exceptions\ModuleNotFoundException;
use Kylin\Modules\Exceptions\ModuleAlreadyExistsException;

/**
 * 模块管理器
 *
 * 负责模块的加载、注册、启动和管理
 */
class ModuleManager
{
    /**
     * 构造函数
     *
     * @param  Container  $app  应用容器
     * @param  string|null  $path  模块路径
     * @param  ModuleCollection|null  $modules  模块集合
     */
    public function __construct(
        private readonly Container $app,
        private string $path = '',
        private ModuleCollection $modules = new ModuleCollection()
    ) {
        $this->path = $this->path ?: $this->config('path', base_path('packages'));
        $this->bootstrap();
    }

    /**
     * 引导模块管理器
     */
    public function bootstrap(): void
    {
        $this->loadModules();
    }

    /**
     * 加载所有模块
     */
    protected function loadModules(): void
    {
        $modules = $this->config('scan.paths', [$this->path]);

        foreach ($modules as $path) {
            $this->scanPath($path);
        }
    }

    /**
     * 扫描路径中的模块
     *
     * @param  string  $path  扫描路径
     */
    protected function scanPath(string $path): void
    {
        if (!is_dir($path)) {
            return;
        }

        $directories = glob($path . '/*', GLOB_ONLYDIR);

        foreach ($directories as $directory) {
            $this->registerModule($directory);
        }
    }

    /**
     * 注册模块
     *
     * @param  string  $path  模块路径
     */
    public function registerModule(string $path): ?Module
    {
        try {
            $module = new Module($this->app, $path);

            if ($this->modules->has($module->getName())) {
                throw new ModuleAlreadyExistsException(
                    "模块 [{$module->getName()}] 已存在。"
                );
            }

            $this->modules->add($module);

            return $module;
        } catch (\Exception) {
            // 跳过无效模块
            return null;
        }
    }

    /**
     * 启动所有模块
     */
    public function boot(): void
    {
        $this->modules->each(function (Module $module): void {
            if ($module->isEnabled()) {
                $module->boot();
            }
        });
    }

    /**
     * 获取所有模块
     */
    public function all(): ModuleCollection
    {
        return $this->modules;
    }

    /**
     * 通过名称获取模块
     *
     * @param  string  $name  模块名称
     * @param  mixed  $default  默认值
     */
    public function get(string $name, mixed $default = null): mixed
    {
        return $this->modules->get($name, $default);
    }

    /**
     * 检查模块是否存在
     *
     * @param  string  $name  模块名称
     */
    public function has(string $name): bool
    {
        return $this->modules->has($name);
    }

    /**
     * 创建新模块
     *
     * @param  string  $name  模块名称
     * @param  array  $attributes  模块属性
     */
    public function make(string $name, array $attributes = []): ?Module
    {
        $path = $this->path . '/' . strtolower($name);

        return $this->registerModule($path);
    }

    /**
     * 获取模块路径
     */
    public function getPath(): string
    {
        return $this->path;
    }

    /**
     * 设置模块路径
     *
     * @param  string  $path  模块路径
     */
    public function setPath(string $path): self
    {
        $this->path = $path;

        return $this;
    }

    /**
     * 获取配置值
     *
     * @param  string  $key  配置键
     * @param  mixed  $default  默认值
     */
    protected function config(string $key, mixed $default = null): mixed
    {
        return $this->app['config']->get("modules.{$key}", $default);
    }

    /**
     * 获取模块集合
     */
    public function getModules(): ModuleCollection
    {
        return $this->modules;
    }

    /**
     * 调用模块方法的魔术方法
     *
     * @param  string  $method  方法名
     * @param  array  $parameters  方法参数
     */
    public function __call(string $method, array $parameters): mixed
    {
        return $this->modules->{$method}(...$parameters);
    }
}