<?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\User;
use App\Service\OperationLogService;
use App\Utils\RequestHelper;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\RequestMapping;
use OpenApi\Attributes as OA;

#[OA\Tag(name: 'Users', description: '用户管理')]
#[Controller(prefix: "/api/v1/users")]
class UserController extends AbstractController
{
    /**
     * 用户列表
     *
     * 支持分页、按 username/email 模糊搜索、按 status/role_id 精确筛选
     */
    #[OA\Get(
        path: '/users',
        summary: '用户列表',
        description: '获取用户列表，支持分页、按 username/email 模糊搜索、按 status/role_id 精确筛选',
        security: [['bearerAuth' => []]],
        tags: ['Users'],
        parameters: [
            new OA\Parameter(name: 'page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 1)),
            new OA\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 15, maximum: 100)),
            new OA\Parameter(name: 'username', in: 'query', required: false, description: '用户名模糊搜索', schema: new OA\Schema(type: 'string')),
            new OA\Parameter(name: 'email', in: 'query', required: false, description: '邮箱模糊搜索', schema: new OA\Schema(type: 'string')),
            new OA\Parameter(name: 'status', in: 'query', required: false, description: '状态筛选（0=禁用，1=启用）', schema: new OA\Schema(type: 'integer', enum: [0, 1])),
            new OA\Parameter(name: 'role_id', in: 'query', required: false, description: '按角色筛选', 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: 'items', type: 'array', items: new OA\Items(ref: '#/components/schemas/User')),
                        new OA\Property(property: 'total', type: 'integer', example: 100),
                        new OA\Property(property: 'page', type: 'integer', example: 1),
                        new OA\Property(property: 'per_page', type: 'integer', example: 15),
                    ], type: 'object'),
                ])
            ),
            new OA\Response(response: 401, description: '未认证', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
        ]
    )]
    #[RequestMapping(path: "", methods: "GET")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function index(): array
    {
        $page = max(1, (int) $this->request->input('page', 1));
        $per_page = min(100, max(1, (int) $this->request->input('per_page', 15)));

        $query = User::query()->with('role');

        // 按 username 模糊搜索
        $username = $this->request->input('username');
        if ($username !== null && $username !== '') {
            $query->where('username', 'like', '%' . $username . '%');
        }

        // 按 email 模糊搜索
        $email = $this->request->input('email');
        if ($email !== null && $email !== '') {
            $query->where('email', 'like', '%' . $email . '%');
        }

        // 按 status 精确筛选
        $status = $this->request->input('status');
        if ($status !== null && $status !== '') {
            $query->where('status', (int) $status);
        }

        // 按 role_id 精确筛选
        $role_id = $this->request->input('role_id');
        if ($role_id !== null && $role_id !== '') {
            $query->where('role_id', (int) $role_id);
        }

        // 按 created_at 降序排序
        $query->orderBy('created_at', 'desc');

        $total = $query->count();
        $items = $query->offset(($page - 1) * $per_page)
            ->limit($per_page)
            ->get();

        return [
            'code' => 0,
            'message' => '获取成功',
            'data' => [
                'items' => $items,
                'total' => $total,
                'page' => $page,
                'per_page' => $per_page,
            ],
        ];
    }

    /**
     * 创建用户
     */
    #[OA\Post(
        path: '/users',
        summary: '创建用户',
        security: [['bearerAuth' => []]],
        tags: ['Users'],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['username', 'password', 'email'],
                properties: [
                    new OA\Property(property: 'username', type: 'string', minLength: 3, maxLength: 20, example: 'new_user'),
                    new OA\Property(property: 'password', type: 'string', minLength: 6, maxLength: 32, example: 'Pass_1234'),
                    new OA\Property(property: 'email', type: 'string', format: 'email', maxLength: 100, example: 'new@example.com'),
                    new OA\Property(property: 'status', type: 'integer', enum: [0, 1], default: 1),
                ]
            )
        ),
        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', ref: '#/components/schemas/User'),
                ])
            ),
            new OA\Response(response: 400, description: '参数校验失败或唯一性冲突', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
            new OA\Response(response: 401, description: '未认证', content: new OA\JsonContent(ref: '#/components/schemas/ErrorResponse')),
        ]
    )]
    #[RequestMapping(path: "", methods: "POST")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function store(): \Psr\Http\Message\ResponseInterface|array
    {
        $username = $this->request->input('username');
        $password = $this->request->input('password');
        $email = $this->request->input('email');
        $status_input = $this->request->input('status');

        if (!is_string($username) || trim($username) === '') {
            return $this->response->json([
                'code' => 400,
                'message' => '用户名不能为空',
            ])->withStatus(400);
        }

        $username = trim($username);
        $username_length = strlen($username);
        if ($username_length < 3 || $username_length > 20) {
            return $this->response->json([
                'code' => 400,
                'message' => '用户名长度需在 3-20 个字符',
            ])->withStatus(400);
        }

        if (!is_string($password) || $password === '') {
            return $this->response->json([
                'code' => 400,
                'message' => '密码不能为空',
            ])->withStatus(400);
        }

        $password_length = strlen($password);
        if ($password_length < 6 || $password_length > 32) {
            return $this->response->json([
                'code' => 400,
                'message' => '密码长度需在 6-32 个字符',
            ])->withStatus(400);
        }

        if (!is_string($email) || trim($email) === '') {
            return $this->response->json([
                'code' => 400,
                'message' => '邮箱不能为空',
            ])->withStatus(400);
        }

        $email = trim($email);
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return $this->response->json([
                'code' => 400,
                'message' => '邮箱格式不正确',
            ])->withStatus(400);
        }

        if (strlen($email) > 100) {
            return $this->response->json([
                'code' => 400,
                'message' => '邮箱长度不能超过 100 个字符',
            ])->withStatus(400);
        }

        if ($status_input === null || $status_input === '') {
            $status = 1;
        } elseif (!is_numeric($status_input) || !in_array((int) $status_input, [0, 1], true)) {
            return $this->response->json([
                'code' => 400,
                'message' => 'status 参数必须为 0 或 1',
            ])->withStatus(400);
        } else {
            $status = (int) $status_input;
        }

        if (User::query()->where('username', $username)->exists()) {
            return $this->response->json([
                'code' => 400,
                'message' => '用户名已存在',
            ])->withStatus(400);
        }

        if (User::query()->where('email', $email)->exists()) {
            return $this->response->json([
                'code' => 400,
                'message' => '邮箱已被注册',
            ])->withStatus(400);
        }

        $user = User::query()->create([
            'username' => $username,
            'password' => $password,
            'email' => $email,
            'status' => $status,
        ]);

        OperationLogService::log(
            user_id: OperationLogService::getCurrentUserId(),
            action: 'user.create',
            target_type: 'user',
            target_id: $user->id,
            description: "创建用户 {$username}",
            detail: ['email' => $email, 'status' => $status],
            ip: RequestHelper::getClientIp($this->request),
        );

        return [
            'code' => 0,
            'message' => '创建成功',
            'data' => $user,
        ];
    }

    /**
     * 用户详情
     *
     * @param int $id 用户 ID
     */
    #[OA\Get(
        path: '/users/{id}',
        summary: '用户详情',
        security: [['bearerAuth' => []]],
        tags: ['Users'],
        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', ref: '#/components/schemas/User'),
                ])
            ),
            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}", methods: "GET")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function show(int $id): \Psr\Http\Message\ResponseInterface|array
    {
        $user = User::query()->with('role')->find($id);

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

        return [
            'code' => 0,
            'message' => '获取成功',
            'data' => $user,
        ];
    }

    /**
     * 更新用户信息
     *
     * @param int $id 用户 ID
     */
    #[OA\Put(
        path: '/users/{id}',
        summary: '更新用户信息',
        description: '更新用户的 username、email 或 ext 字段，不支持修改密码',
        security: [['bearerAuth' => []]],
        tags: ['Users'],
        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(properties: [
                new OA\Property(property: 'username', type: 'string', minLength: 3, maxLength: 20, example: 'updated_user'),
                new OA\Property(property: 'email', type: 'string', format: 'email', maxLength: 100, example: 'updated@example.com'),
                new OA\Property(property: 'ext', type: 'object', nullable: true, example: ['nickname' => 'Tester']),
            ])
        ),
        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', ref: '#/components/schemas/User'),
                ])
            ),
            new OA\Response(response: 400, description: '参数校验失败或唯一性冲突', 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}", methods: "PUT")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function update(int $id): \Psr\Http\Message\ResponseInterface|array
    {
        $user = User::query()->find($id);

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

        if ($this->request->input('password') !== null) {
            return $this->response->json([
                'code' => 400,
                'message' => '更新接口不支持修改密码',
            ])->withStatus(400);
        }

        $username = $this->request->input('username');
        $email = $this->request->input('email');
        $ext = $this->request->input('ext');
        $updates = [];

        if ($username !== null) {
            if (!is_string($username) || trim($username) === '') {
                return $this->response->json([
                    'code' => 400,
                    'message' => '用户名不能为空',
                ])->withStatus(400);
            }

            $username = trim($username);
            $username_length = strlen($username);
            if ($username_length < 3 || $username_length > 20) {
                return $this->response->json([
                    'code' => 400,
                    'message' => '用户名长度需在 3-20 个字符',
                ])->withStatus(400);
            }

            if (User::query()->where('username', $username)->where('id', '!=', $user->id)->exists()) {
                return $this->response->json([
                    'code' => 400,
                    'message' => '用户名已存在',
                ])->withStatus(400);
            }

            $updates['username'] = $username;
        }

        if ($email !== null) {
            if (!is_string($email) || trim($email) === '') {
                return $this->response->json([
                    'code' => 400,
                    'message' => '邮箱不能为空',
                ])->withStatus(400);
            }

            $email = trim($email);
            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                return $this->response->json([
                    'code' => 400,
                    'message' => '邮箱格式不正确',
                ])->withStatus(400);
            }

            if (strlen($email) > 100) {
                return $this->response->json([
                    'code' => 400,
                    'message' => '邮箱长度不能超过 100 个字符',
                ])->withStatus(400);
            }

            if (User::query()->where('email', $email)->where('id', '!=', $user->id)->exists()) {
                return $this->response->json([
                    'code' => 400,
                    'message' => '邮箱已被注册',
                ])->withStatus(400);
            }

            $updates['email'] = $email;
        }

        if ($ext !== null) {
            if (!is_array($ext)) {
                return $this->response->json([
                    'code' => 400,
                    'message' => 'ext 必须为对象',
                ])->withStatus(400);
            }

            $updates['ext'] = $ext;
        }

        if ($updates === []) {
            return $this->response->json([
                'code' => 400,
                'message' => '缺少可更新字段',
            ])->withStatus(400);
        }

        $user->fill($updates);
        $user->save();
        $user->refresh();

        OperationLogService::log(
            user_id: OperationLogService::getCurrentUserId(),
            action: 'user.update',
            target_type: 'user',
            target_id: $user->id,
            description: "更新用户 {$user->username} 信息",
            detail: $updates,
            ip: RequestHelper::getClientIp($this->request),
        );

        return [
            'code' => 0,
            'message' => '更新成功',
            'data' => $user,
        ];
    }

    /**
     * 更新用户状态
     *
     * @param int $id 用户 ID
     */
    #[OA\Patch(
        path: '/users/{id}/status',
        summary: '更新用户状态',
        description: '启用或禁用用户',
        security: [['bearerAuth' => []]],
        tags: ['Users'],
        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: ['status'],
                properties: [
                    new OA\Property(property: 'status', type: 'integer', enum: [0, 1], description: '0=禁用，1=启用'),
                ]
            )
        ),
        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', ref: '#/components/schemas/User'),
                ])
            ),
            new OA\Response(response: 400, description: '参数校验失败', 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}/status", methods: "PATCH")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function updateStatus(int $id): \Psr\Http\Message\ResponseInterface|array
    {
        $user = User::query()->find($id);

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

        $status_input = $this->request->input('status');
        if ($status_input === null || $status_input === '') {
            return $this->response->json([
                'code' => 400,
                'message' => '缺少 status 参数',
            ])->withStatus(400);
        }

        if (!is_numeric($status_input) || !in_array((int) $status_input, [0, 1], true)) {
            return $this->response->json([
                'code' => 400,
                'message' => 'status 参数必须为 0 或 1',
            ])->withStatus(400);
        }

        $old_status = $user->status;
        $user->status = (int) $status_input;
        $user->save();
        $user->refresh();

        OperationLogService::log(
            user_id: OperationLogService::getCurrentUserId(),
            action: 'user.status_change',
            target_type: 'user',
            target_id: $user->id,
            description: "用户 {$user->username} 状态变更",
            detail: ['old_status' => $old_status, 'new_status' => $user->status],
            ip: RequestHelper::getClientIp($this->request),
        );

        return [
            'code' => 0,
            'message' => '状态更新成功',
            'data' => $user,
        ];
    }

    /**
     * 管理员切换用户 API Key 权限
     */
    #[OA\Patch(
        path: '/users/{id}/api-key-enabled',
        summary: '切换用户 API Key 权限',
        description: '管理员切换指定用户的 api_key_enabled 全局开关。关闭后该用户所有 Key 无法认证，重新开启后自动恢复',
        security: [['bearerAuth' => []]],
        tags: ['Users'],
        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: ['api_key_enabled'],
                properties: [
                    new OA\Property(property: 'api_key_enabled', type: 'boolean', description: '是否启用 API Key 功能'),
                ]
            )
        ),
        responses: [
            new OA\Response(
                response: 200,
                description: 'API Key 权限更新成功',
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: 'code', type: 'integer', example: 0),
                    new OA\Property(property: 'message', type: 'string', example: 'API Key 权限更新成功'),
                    new OA\Property(property: 'data', properties: [
                        new OA\Property(property: 'id', type: 'integer'),
                        new OA\Property(property: 'username', type: 'string'),
                        new OA\Property(property: 'api_key_enabled', type: 'boolean'),
                    ], type: 'object'),
                ])
            ),
            new OA\Response(response: 400, description: '参数错误', 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: 403, 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}/api-key-enabled", methods: "PATCH")]
    #[Middleware(AuthMiddleware::class)]
    #[Middleware(PermissionMiddleware::class)]
    public function updateApiKeyEnabled(int $id): \Psr\Http\Message\ResponseInterface|array
    {
        $user = User::query()->find($id);

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

        $api_key_enabled = filter_var($this->request->input('api_key_enabled'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        if ($api_key_enabled === null) {
            return $this->response->json([
                'code' => 400,
                'message' => 'api_key_enabled 参数不能为空或格式不正确',
            ])->withStatus(400);
        }

        $user->api_key_enabled = $api_key_enabled;
        $user->save();

        return [
            'code' => 0,
            'message' => 'API Key 权限更新成功',
            'data' => [
                'id' => $user->id,
                'username' => $user->username,
                'api_key_enabled' => $user->api_key_enabled,
            ],
        ];
    }
}
