<?php

declare(strict_types=1);

namespace App\Controller\Api\V1;

use App\Controller\AbstractController;
use App\Middleware\AuthMiddleware;
use App\Middleware\PermissionMiddleware;
use App\Model\Company;
use App\Service\OperationLogService;
use App\Utils\RequestHelper;
use App\Model\Platform;
use App\Model\Store;
use App\Model\User;
use App\Model\UserDataScope;
use App\Service\ScopeBitmapService;
use App\Service\ScopeTableManager;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\RequestMapping;
use OpenApi\Attributes as OA;
use Psr\Http\Message\ResponseInterface;

#[OA\Tag(name: 'Data Scope', description: '用户数据范围管理')]
#[Controller(prefix: "/api/v1/users")]
class DataScopeController extends AbstractController
{
    public function __construct(
        protected readonly ScopeTableManager $scopeTableManager,
        protected readonly ScopeBitmapService $bitmapService,
    ) {
    }

    /**
     * 查看用户数据权限
     *
     * 返回用户的 scope 列表（含实体名称）和解析后的 store_ids
     *
     * @param int $id 用户 ID
     */
    #[OA\Get(
        path: '/users/{id}/data-scope',
        summary: '查看用户数据权限',
        description: '返回用户的 scope 列表（含实体名称）和解析后的 store_ids',
        security: [['bearerAuth' => []]],
        tags: ['Data Scope'],
        parameters: [
            new OA\Parameter(name: 'id', in: 'path', required: true, description: '用户 ID', schema: new OA\Schema(type: 'integer')),
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: '获取成功',
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: 'code', type: 'integer', example: 0),
                    new OA\Property(property: 'message', type: 'string', example: '获取成功'),
                    new OA\Property(property: 'data', properties: [
                        new OA\Property(property: 'user_id', type: 'integer', example: 1),
                        new OA\Property(property: 'role', type: 'string', example: 'admin'),
                        new OA\Property(
                            property: 'scopes',
                            type: 'array',
                            items: new OA\Items(properties: [
                                new OA\Property(property: 'scope_type', type: 'string', example: 'company'),
                                new OA\Property(property: 'scope_id', type: 'integer', example: 1),
                                new OA\Property(property: 'name', type: 'string', example: '示例公司'),
                            ], type: 'object')
                        ),
                        new OA\Property(property: 'resolved_store_ids', type: 'array', items: new OA\Items(type: 'integer'), example: [1, 2, 3]),
                    ], type: 'object'),
                ])
            ),
            new OA\Response(response: 401, description: '未认证', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
            new OA\Response(response: 404, description: '用户不存在', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
        ]
    )]
    #[RequestMapping(path: "{id}/data-scope", methods: "GET")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function show(int $id): ResponseInterface|array
    {
        $user = User::query()->with('role')->find($id);

        if (!$user) {
            return $this->response->json([
                'code' => 404,
                'message' => '用户不存在',
            ])->withStatus(404);
        }

        $scopes = UserDataScope::query()->where('user_id', $id)->get();

        // 批量查询实体名称，避免 N+1
        $scope_data = $this->enrichScopes($scopes->toArray());

        // 解析最终 store_ids
        $resolved_store_ids = [];
        if ($user->role && $user->role->name !== 'administrator') {
            $bitmap = $this->bitmapService->buildForUser($id);
            $resolved_store_ids = $this->bitmapService->decode($bitmap);
        }

        return [
            'code' => 0,
            'message' => '获取成功',
            'data' => [
                'user_id' => $id,
                'role' => $user->role?->name,
                'scopes' => $scope_data,
                'resolved_store_ids' => $resolved_store_ids,
            ],
        ];
    }

    /**
     * 设置用户数据权限
     *
     * 全量替换用户的 scope 绑定，并重建 bitmap
     *
     * @param int $id 用户 ID
     */
    #[OA\Put(
        path: '/users/{id}/data-scope',
        summary: '设置用户数据权限',
        description: '全量替换用户的 scope 绑定，并重建 bitmap',
        security: [['bearerAuth' => []]],
        tags: ['Data Scope'],
        parameters: [
            new OA\Parameter(name: 'id', in: 'path', required: true, description: '用户 ID', schema: new OA\Schema(type: 'integer')),
        ],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['scopes'],
                properties: [
                    new OA\Property(
                        property: 'scopes',
                        type: 'array',
                        items: new OA\Items(
                            required: ['scope_type', 'scope_id'],
                            properties: [
                                new OA\Property(property: 'scope_type', type: 'string', enum: ['company', 'platform', 'store'], example: 'company'),
                                new OA\Property(property: 'scope_id', type: 'integer', example: 1),
                            ],
                            type: 'object'
                        )
                    ),
                ]
            )
        ),
        responses: [
            new OA\Response(
                response: 200,
                description: '数据权限更新成功',
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: 'code', type: 'integer', example: 0),
                    new OA\Property(property: 'message', type: 'string', example: '数据权限更新成功'),
                ])
            ),
            new OA\Response(response: 400, description: '参数校验失败（无效 scope_type 等）', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
            new OA\Response(response: 401, description: '未认证', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
            new OA\Response(response: 404, description: '用户不存在', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
        ]
    )]
    #[RequestMapping(path: "{id}/data-scope", methods: "PUT")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function update(int $id): ResponseInterface|array
    {
        $user = User::query()->with('role')->find($id);

        if (!$user) {
            return $this->response->json([
                'code' => 404,
                'message' => '用户不存在',
            ])->withStatus(404);
        }

        $body = $this->request->getParsedBody();

        if (!array_key_exists('scopes', $body)) {
            return $this->response->json([
                'code' => 400,
                'message' => '缺少 scopes 参数',
            ])->withStatus(400);
        }

        $scopes = $body['scopes'];

        if (!is_array($scopes)) {
            return $this->response->json([
                'code' => 400,
                'message' => 'scopes 必须为数组',
            ])->withStatus(400);
        }

        // 校验每条 scope
        $valid_scope_types = ['company', 'platform', 'store'];
        $records = [];
        foreach ($scopes as $item) {
            if (!is_array($item) || !isset($item['scope_type']) || !isset($item['scope_id'])) {
                return $this->response->json([
                    'code' => 400,
                    'message' => '每条 scope 必须包含 scope_type 和 scope_id',
                ])->withStatus(400);
            }

            if (!in_array($item['scope_type'], $valid_scope_types, true)) {
                return $this->response->json([
                    'code' => 400,
                    'message' => "scope_type 必须为 company、platform 或 store",
                ])->withStatus(400);
            }

            $records[] = [
                'user_id' => $id,
                'scope_type' => $item['scope_type'],
                'scope_id' => (int) $item['scope_id'],
                'created_at' => date('Y-m-d H:i:s'),
            ];
        }

        // 事务内全量替换
        Db::beginTransaction();
        try {
            UserDataScope::query()->where('user_id', $id)->delete();

            if (!empty($records)) {
                UserDataScope::query()->insert($records);
            }

            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            throw $e;
        }

        // 重建 bitmap 并更新 Swoole\Table
        $this->scopeTableManager->rebuildUserScope($id);

        OperationLogService::log(
            user_id: OperationLogService::getCurrentUserId(),
            action: 'scope.update',
            target_type: 'user',
            target_id: $id,
            description: "更新用户 #{$id} 数据权限",
            detail: ['scopes' => $scopes],
            ip: RequestHelper::getClientIp($this->request),
        );

        return [
            'code' => 0,
            'message' => '数据权限更新成功',
        ];
    }

    /**
     * 批量查询 scope 关联的实体名称
     *
     * @param array $scopes scope 记录数组
     * @return array 带名称的 scope 列表
     */
    protected function enrichScopes(array $scopes): array
    {
        if (empty($scopes)) {
            return [];
        }

        // 按 scope_type 分组收集 IDs
        $company_ids = [];
        $platform_ids = [];
        $store_ids = [];

        foreach ($scopes as $scope) {
            match ($scope['scope_type']) {
                'company' => $company_ids[] = $scope['scope_id'],
                'platform' => $platform_ids[] = $scope['scope_id'],
                'store' => $store_ids[] = $scope['scope_id'],
                default => null,
            };
        }

        // 批量查询名称
        $company_names = !empty($company_ids)
            ? Company::query()->whereIn('id', $company_ids)->pluck('label', 'id')->toArray()
            : [];
        $platform_names = !empty($platform_ids)
            ? Platform::query()->whereIn('id', $platform_ids)->pluck('name', 'id')->toArray()
            : [];
        $store_names = !empty($store_ids)
            ? Store::query()->whereIn('id', $store_ids)->pluck('label', 'id')->toArray()
            : [];

        // 组装结果
        return array_map(function (array $scope) use ($company_names, $platform_names, $store_names): array {
            $name = match ($scope['scope_type']) {
                'company' => $company_names[$scope['scope_id']] ?? null,
                'platform' => $platform_names[$scope['scope_id']] ?? null,
                'store' => $store_names[$scope['scope_id']] ?? null,
                default => null,
            };

            return [
                'scope_type' => $scope['scope_type'],
                'scope_id' => $scope['scope_id'],
                'name' => $name,
            ];
        }, $scopes);
    }
}
