<?php

declare(strict_types=1);

namespace App\Middleware;

use App\Model\Platform;
use App\Model\RoleRouteOverride;
use App\Model\Route;
use App\Model\Store;
use App\Service\ScopeBitmapService;
use App\Service\ScopeTableManager;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Hyperf\HttpServer\Router\Dispatched;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Qbhy\HyperfAuth\AuthManager;

class PermissionMiddleware implements MiddlewareInterface
{
    public function __construct(
        protected readonly AuthManager $auth,
        protected readonly HttpResponse $response,
        protected readonly ScopeTableManager $scopeTableManager,
        protected readonly ScopeBitmapService $bitmapService,
    ) {
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // 获取已认证用户（优先从 attribute 获取，兼容 JWT guard）
        $user = $request->getAttribute('auth_user') ?? $this->auth->guard('jwt')->user();
        if (!$user) {
            return $this->forbiddenResponse('用户认证异常');
        }

        // 获取用户 scope（含角色和 bitmap）
        $user_scope = $this->scopeTableManager->getUserScope($user->id);
        if (!$user_scope) {
            return $this->forbiddenResponse('用户权限未配置');
        }

        $role = $user_scope['role'];
        $method = $request->getMethod();

        // 通过 Dispatched 获取路由模板路径（如 /api/v1/users/{id}），解决参数化路由匹配问题
        $dispatched = $request->getAttribute(Dispatched::class);
        $route_path = $dispatched?->handler?->route ?? $request->getUri()->getPath();

        // ===== Step 1: 路由访问检查 =====
        if ($role !== 'administrator') {
            $access_result = $this->checkRouteAccess($user->role_id, $method, $route_path);
            if ($access_result === false) {
                return $this->forbiddenResponse('无权访问该接口');
            }
        }

        // ===== Step 2: 数据范围检查 =====
        $scope_result = $this->applyDataScope($request, $role, $user_scope['scope'], $user);
        if ($scope_result instanceof ResponseInterface) {
            return $scope_result;
        }

        return $handler->handle($scope_result);
    }

    /**
     * 路由访问检查
     *
     * @param int $role_id
     * @param string $method
     * @param string $path
     * @return bool
     */
    protected function checkRouteAccess(int $role_id, string $method, string $path): bool
    {
        // 查找路由记录
        $route = Route::query()->where('method', $method)->where('path', $path)->first();
        if (!$route) {
            // 白名单模式：未注册到 routes 表的路由拒绝访问
            return false;
        }

        // 1. 先查 override（优先级最高）
        $override = RoleRouteOverride::query()
            ->where('role_id', $role_id)
            ->where('route_id', $route->id)
            ->first();
        if ($override) {
            return $override->allowed;
        }

        // 2. 查 route group 授权
        if (!$route->group_id) {
            // 路由未分组且无 override → 拒绝
            return false;
        }

        return Db::table('role_route_groups')
            ->where('role_id', $role_id)
            ->where('group_id', $route->group_id)
            ->exists();
    }

    /**
     * 数据范围检查与注入
     *
     * @return ServerRequestInterface|ResponseInterface
     */
    protected function applyDataScope(
        ServerRequestInterface $request,
        string $role,
        string $bitmap,
        mixed $user,
    ): ServerRequestInterface|ResponseInterface {
        $params = $request->getQueryParams();
        $company_id = isset($params['company_id']) ? (int) $params['company_id'] : null;
        $platform_id = isset($params['platform_id']) ? (int) $params['platform_id'] : null;
        $store_id = isset($params['store_id']) ? (int) $params['store_id'] : null;

        // --- administrator: 全部放行 ---
        if ($role === 'administrator') {
            $request = $request->withAttribute('scope_type', 'all');
            $request = $request->withAttribute('scope_ids', []);
            return $request;
        }

        // --- developer: 基于维护的 platform ---
        if ($role === 'developer') {
            return $this->applyDeveloperScope($request, $user, $bitmap, $company_id, $platform_id, $store_id);
        }

        // --- accessor: 基于 bitmap store_ids ---
        return $this->applyAccessorScope($request, $bitmap, $company_id, $platform_id, $store_id);
    }

    /**
     * developer 角色的数据范围处理
     *
     * @return ServerRequestInterface|ResponseInterface
     */
    protected function applyDeveloperScope(
        ServerRequestInterface $request,
        mixed $user,
        string $bitmap,
        ?int $company_id,
        ?int $platform_id,
        ?int $store_id,
    ): ServerRequestInterface|ResponseInterface {
        $platform_ids = Platform::query()->where('developer_id', $user->id)->pluck('id')->toArray();

        // 有 scope 参数时校验
        if ($platform_id !== null && !in_array($platform_id, $platform_ids, true)) {
            return $this->forbiddenResponse('平台不在开发者权限范围内');
        }
        if ($store_id !== null && !$this->bitmapService->has($bitmap, $store_id)) {
            return $this->forbiddenResponse('店铺不在开发者权限范围内');
        }
        if ($company_id !== null) {
            $has_store = Store::query()
                ->where('company_id', $company_id)
                ->whereIn('platform_id', $platform_ids)
                ->exists();
            if (!$has_store) {
                return $this->forbiddenResponse('公司不在开发者权限范围内');
            }
        }

        // 注入 scope
        if ($platform_id === null && $store_id === null && $company_id === null) {
            $request = $request->withAttribute('scope_type', 'platform');
            $request = $request->withAttribute('scope_ids', $platform_ids);
        } else {
            $request = $request->withAttribute('scope_type', 'store');
            $request = $request->withAttribute('scope_ids', $this->bitmapService->decode($bitmap));
        }

        return $request;
    }

    /**
     * accessor 角色的数据范围处理
     *
     * @return ServerRequestInterface|ResponseInterface
     */
    protected function applyAccessorScope(
        ServerRequestInterface $request,
        string $bitmap,
        ?int $company_id,
        ?int $platform_id,
        ?int $store_id,
    ): ServerRequestInterface|ResponseInterface {
        $allowed_store_ids = $this->bitmapService->decode($bitmap);

        // 有 scope 参数时校验
        if ($store_id !== null && !$this->bitmapService->has($bitmap, $store_id)) {
            return $this->forbiddenResponse('店铺不在访问权限范围内');
        }
        if ($company_id !== null) {
            $company_stores = Store::query()->where('company_id', $company_id)->pluck('id')->toArray();
            if (empty(array_intersect($company_stores, $allowed_store_ids))) {
                return $this->forbiddenResponse('公司不在访问权限范围内');
            }
        }
        if ($platform_id !== null) {
            $platform_stores = Store::query()->where('platform_id', $platform_id)->pluck('id')->toArray();
            if (empty(array_intersect($platform_stores, $allowed_store_ids))) {
                return $this->forbiddenResponse('平台不在访问权限范围内');
            }
        }

        // 注入已验证的 store_ids
        $request = $request->withAttribute('scope_type', 'store');
        $request = $request->withAttribute('scope_ids', $allowed_store_ids);

        return $request;
    }

    /**
     * 返回 403 响应
     */
    protected function forbiddenResponse(string $message): ResponseInterface
    {
        return $this->response->json([
            'code' => 403,
            'message' => $message,
        ])->withStatus(403);
    }
}
