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

use Core\service\registry\ApplicationRegistry;
use app\repository\module\ModuleManifestRepository;


/**
 * 行业/应用启用状态守卫
 * 拦截已关闭应用和已禁用模块/插件的接口请求
 * @package app\middleware
 */
class ApplicationGuard
{

    private const CORE_PREFIXES = ['sys', 'core', 'adminapi'];


    private static array $disabledSubCache = [];


    /**
     * 处理应用启用状态守卫
     * @param mixed $request
     * @param \Closure $next
     * @return mixed
     */
    public function handle($request, \Closure $next)
    {
        $path = trim((string)$request->pathinfo(), '/');
        if ($path === '') {
            return $next($request);
        }

        $segments = explode('/', $path);
        $firstSegment = strtolower($segments[0]);


        if (in_array($firstSegment, self::CORE_PREFIXES, true)) {
            return $next($request);
        }


        try {
            /** @var ApplicationRegistry $registry */
            $registry = app()->make(ApplicationRegistry::class);
            /** @var ModuleManifestRepository $moduleRepo */
            $moduleRepo = app()->make(ModuleManifestRepository::class);
        } catch (\Throwable $e) {
            return $next($request);
        }

        $enabled = $registry->enabledCodes();


        if (!in_array($firstSegment, $enabled, true)) {
            $installed = $registry->installedCodes();
            if (in_array($firstSegment, $installed, true)) {
                return json(['code' => 403, 'msg' => ''], 403);
            }

            return $next($request);
        }


        if (isset($segments[1])) {
            $result = $this->checkSubEnabled($firstSegment, $segments, $moduleRepo);
            if ($result !== null) {
                return $result;
            }
        }

        return $next($request);
    }


    /**
     * 检查子模块/插件是否已启用
     * @param string $appCode 应用编码
     * @param array $segments URL路径分段
     * @param ModuleManifestRepository $moduleRepo 模块仓储
     * @return \think\response\Json|null 禁用时返回403响应，否则null
     */
    private function checkSubEnabled(string $appCode, array $segments, ModuleManifestRepository $moduleRepo): ?\think\response\Json
    {
        $subCode = $this->extractSubCode($segments);
        if ($subCode === null) {
            return null;
        }

        $fullCode = $appCode . '.' . $subCode;
        $cacheKey = $fullCode;


        if (array_key_exists($cacheKey, self::$disabledSubCache)) {
            return self::$disabledSubCache[$cacheKey] ? json(['code' => 403, 'msg' => ''], 403) : null;
        }

        try {
            $record = $moduleRepo->findByCode($fullCode);
            if (is_array($record) && (int)($record['status'] ?? 1) !== 1) {
                self::$disabledSubCache[$cacheKey] = true;
                return json(['code' => 403, 'msg' => ''], 403);
            }
            self::$disabledSubCache[$cacheKey] = false;
        } catch (\Throwable $e) {

            self::$disabledSubCache[$cacheKey] = false;
        }

        return null;
    }


    /**
     * 从路径分段提取子模块/插件编码
     * @param array $segments 路径分段
     * @return string|null
     */
    private function extractSubCode(array $segments): ?string
    {
        if (count($segments) < 2) {
            return null;
        }


        if (strtolower($segments[1]) === 'plugins' && isset($segments[2])) {
            return strtolower($segments[2]);
        }


        return strtolower($segments[1]);
    }
}