<?php

/**
 * 文件功能：后台用户大盘管理控制器
 * (替代原版 gl/ 下的各种管理面)
 *
 * @author   ChatRoom Laravel
 *
 * @version  1.0.0
 */

namespace App\Http\Controllers\Admin;

use App\Enums\CurrencySource;
use App\Events\AppointmentAnnounced;
use App\Events\UserBrowserRefreshRequested;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\UpdateManagedUserRequest;
use App\Models\Department;
use App\Models\Position;
use App\Models\User;
use App\Models\UserPosition;
use App\Services\AppointmentService;
use App\Services\ChatStateService;
use App\Services\UserCurrencyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\View\View;

/**
 * 类功能：负责后台用户列表展示、资料编辑与删除操作。
 */
class UserManagerController extends Controller
{
    /**
     * 注入统一积分服务和聊天室状态服务
     */
    public function __construct(
        private readonly UserCurrencyService $currencyService,
        private readonly ChatStateService $chatState,
        private readonly AppointmentService $appointmentService,
    ) {}

    /**
     * 显示用户列表及搜索（支持按等级/经验/金币/魅力/在线状态排序）
     */
    public function index(Request $request): View
    {
        $query = User::query();

        if ($request->filled('username')) {
            $query->where('username', 'like', '%'.$request->input('username').'%');
        }

        // 从 Redis 获取所有在线用户名（跨所有房间去重）
        $onlineUsernames = collect();
        foreach ($this->chatState->getAllActiveRoomIds() as $roomId) {
            $onlineUsernames = $onlineUsernames->merge(array_keys($this->chatState->getRoomUsers($roomId)));
        }
        $onlineUsernames = $onlineUsernames->unique()->values();

        // 排序：允许的字段白名单，防止 SQL 注入
        $sortable = ['user_level', 'exp_num', 'jjb', 'meili', 'id', 'online', 'wxid'];
        $sortBy = in_array($request->input('sort_by'), $sortable) ? $request->input('sort_by') : 'id';
        $sortDir = $request->input('sort_dir') === 'asc' ? 'asc' : 'desc';

        if ($sortBy === 'online') {
            // 用虚拟列排序：在线用户标记为 1，离线为 0；desc = 在线优先
            if ($onlineUsernames->isNotEmpty()) {
                $placeholders = implode(',', array_fill(0, $onlineUsernames->count(), '?'));
                $query->orderByRaw(
                    "CASE WHEN username IN ({$placeholders}) THEN 1 ELSE 0 END {$sortDir}",
                    $onlineUsernames->toArray(),
                );
            }
            $query->orderBy('id', 'desc'); // 二级排序
        } else {
            $query->orderBy($sortBy, $sortDir);
        }

        $users = $query
            ->with(['activePosition.position.department', 'vipLevel'])
            ->paginate(20)
            ->withQueryString();

        // VIP 等级选项列表（供编辑弹窗使用）
        $vipLevels = \App\Models\VipLevel::orderBy('sort_order')->get();
        // 职务下拉选项（复用任命系统中的部门与职务数据）
        $departments = Department::with([
            'positions' => fn ($positionQuery) => $positionQuery->ordered(),
        ])->ordered()->get();

        return view('admin.users.index', compact('users', 'vipLevels', 'departments', 'sortBy', 'sortDir', 'onlineUsernames'));
    }

    /**
     * 修改用户资料、等级或密码 (AJAX 或表单)
     *
     * @param  User  $user  路由模型自动注入
     */
    public function update(UpdateManagedUserRequest $request, User $user): JsonResponse|RedirectResponse
    {
        $targetUser = $user;
        $currentUser = Auth::user();
        $responseMessages = [];

        // 超级管理员专属：仅 id=1 的账号可编辑用户信息
        if ($currentUser->id !== 1) {
            if ($request->wantsJson()) {
                return response()->json(['status' => 'error', 'message' => '仅超级管理员（id=1）可编辑用户信息。'], 403);
            }
            abort(403, '仅超级管理员（id=1）可编辑用户信息。');
        }

        // 越权防护：不能修改 等级大于或等于自己 的目标（除非修改自己）
        if ($targetUser->id !== $currentUser->id && $targetUser->user_level >= $currentUser->user_level) {
            return response()->json(['status' => 'error', 'message' => '权限不足：您无法修改同级或高级管理人员资料。'], 403);
        }

        $validated = $request->validated();

        if (isset($validated['sex'])) {
            $targetUser->sex = $validated['sex'];
        }
        if (isset($validated['exp_num'])) {
            // 计算差值并通过统一服务记录流水（管理员手动调整）
            $expDiff = $validated['exp_num'] - ($targetUser->exp_num ?? 0);
            if ($expDiff !== 0) {
                $this->currencyService->change(
                    $targetUser, 'exp', $expDiff, CurrencySource::ADMIN_ADJUST,
                    "管理员 {$currentUser->username} 手动调整经验",
                );
                $targetUser->refresh();
            }

            // 调整经验后重新计算等级（有职务用户锁定职务等级，无职务用户按经验重算）
            $targetUser->load('activePosition.position');
            $superLevel = (int) \App\Models\Sysparam::getValue('superlevel', '100');
            if ($targetUser->activePosition?->position) {
                // 有在职职务：等级锁定为职务级，不受经验影响
                $lockedLevel = (int) $targetUser->activePosition->position->level;
                if ($lockedLevel > 0 && $targetUser->user_level !== $lockedLevel) {
                    $targetUser->user_level = $lockedLevel;
                }
            } elseif ($targetUser->user_level < $superLevel) {
                // 无职务普通用户：按经验重算等级（不超过满级阈值）
                $newLevel = \App\Models\Sysparam::calculateLevel($targetUser->exp_num ?? 0);
                $safeLevel = max(1, min($newLevel, $superLevel - 1));
                $targetUser->user_level = $safeLevel;
            }
        }

        if (isset($validated['jjb'])) {
            $jjbDiff = $validated['jjb'] - ($targetUser->jjb ?? 0);
            if ($jjbDiff !== 0) {
                $this->currencyService->change(
                    $targetUser, 'gold', $jjbDiff, CurrencySource::ADMIN_ADJUST,
                    "管理员 {$currentUser->username} 手动调整金币",
                );
                $targetUser->refresh();
            }
        }
        if (isset($validated['meili'])) {
            $meiliDiff = $validated['meili'] - ($targetUser->meili ?? 0);
            if ($meiliDiff !== 0) {
                $this->currencyService->change(
                    $targetUser, 'charm', $meiliDiff, CurrencySource::ADMIN_ADJUST,
                    "管理员 {$currentUser->username} 手动调整魅力",
                );
                $targetUser->refresh();
            }
        }
        if (array_key_exists('qianming', $validated)) {
            $targetUser->qianming = $validated['qianming'];
        }
        if (isset($validated['headface'])) {
            $targetUser->headface = $validated['headface'];
        }

        // VIP 会员等级设置
        if (array_key_exists('vip_level_id', $validated)) {
            $targetUser->vip_level_id = $validated['vip_level_id'] ?: null;
        }
        if (array_key_exists('hy_time', $validated)) {
            $targetUser->hy_time = $validated['hy_time'] ?: null;
        }

        if (! empty($validated['password'])) {
            $targetUser->password = Hash::make($validated['password']);
        }

        $targetUser->save();

        if (array_key_exists('position_id', $validated)) {
            $positionSyncResult = $this->syncUserPosition(
                operator: $currentUser,
                targetUser: $targetUser,
                targetPositionId: $validated['position_id'],
            );

            if (! $positionSyncResult['ok']) {
                return response()->json(['status' => 'error', 'message' => $positionSyncResult['message']], 422);
            }

            if (! empty($positionSyncResult['message'])) {
                $responseMessages[] = $positionSyncResult['message'];
            }
        }

        if ($request->wantsJson()) {
            $message = array_merge(['用户资料已强行更新完毕！'], $responseMessages);

            return response()->json(['status' => 'success', 'message' => implode(' ', $message)]);
        }

        $message = array_merge(['用户资料已更新！'], $responseMessages);

        return back()->with('success', implode(' ', $message));
    }

    /**
     * 物理删除杀封用户
     *
     * @param  User  $user  路由模型自动注入
     */
    public function destroy(Request $request, User $user): RedirectResponse
    {
        $targetUser = $user;
        $currentUser = Auth::user();

        // 超级管理员专属：仅 id=1 的账号可删除用户
        if ($currentUser->id !== 1) {
            abort(403, '仅超级管理员（id=1）可删除用户。');
        }

        // 越权防护：不允许删除同级或更高等级的账号
        if ($targetUser->id !== $currentUser->id && $targetUser->user_level >= $currentUser->user_level) {
            abort(403, '权限不足：无法删除同级或高级账号！');
        }

        // 管理员保护：达到踢人等级(level_kick)的用户视为管理员，不可被强杀
        $levelKick = (int) \App\Models\Sysparam::getValue('level_kick', '10');
        if ($targetUser->user_level >= $levelKick) {
            abort(403, '该用户为管理员，不允许强杀！请先在用户编辑中降低其等级。');
        }

        $targetUser->delete();

        return back()->with('success', '目标已被物理删除。');
    }

    /**
     * 方法功能：同步后台编辑页选择的目标职务。
     *
     * @return array{ok: bool, message: string}
     */
    private function syncUserPosition(User $operator, User $targetUser, ?int $targetPositionId): array
    {
        $currentAssignment = $this->appointmentService->getActivePosition($targetUser);
        $currentPositionId = $currentAssignment?->position_id;

        if ($targetPositionId === $currentPositionId) {
            return ['ok' => true, 'message' => ''];
        }

        if ($targetPositionId === null) {
            if (! $currentAssignment) {
                return ['ok' => true, 'message' => ''];
            }

            $result = $this->appointmentService->revoke($operator, $targetUser, '后台用户管理编辑');
            if (! $result['ok']) {
                return $result;
            }

            $this->broadcastRevokedPosition($operator, $targetUser, $currentAssignment);

            return ['ok' => true, 'message' => '用户职务已撤销。'];
        }

        $targetPosition = Position::with('department')->findOrFail($targetPositionId);

        if ($currentAssignment) {
            $revokeResult = $this->appointmentService->revoke($operator, $targetUser, '后台用户管理编辑');
            if (! $revokeResult['ok']) {
                return $revokeResult;
            }
        }

        $appointResult = $this->appointmentService->appoint($operator, $targetUser, $targetPosition, '后台用户管理编辑');
        if (! $appointResult['ok']) {
            return $appointResult;
        }

        $this->broadcastAppointedPosition($operator, $targetUser, $targetPosition);

        return ['ok' => true, 'message' => "用户职务已更新为【{$targetPosition->name}】。"];
    }

    /**
     * 方法功能：广播后台任命成功后的公告与目标用户刷新事件。
     */
    private function broadcastAppointedPosition(User $operator, User $targetUser, Position $targetPosition): void
    {
        foreach ($this->chatState->getAllActiveRoomIds() as $roomId) {
            broadcast(new AppointmentAnnounced(
                roomId: $roomId,
                targetUsername: $targetUser->username,
                positionIcon: $targetPosition->icon ?? '🎖️',
                positionName: $targetPosition->name,
                departmentName: $targetPosition->department?->name ?? '',
                operatorName: $operator->username,
            ));
        }

        broadcast(new UserBrowserRefreshRequested(
            targetUserId: $targetUser->id,
            operator: $operator->username,
            reason: '你的职务已发生变更，页面权限正在同步更新。',
        ));
    }

    /**
     * 方法功能：广播后台撤销职务后的公告与目标用户刷新事件。
     */
    private function broadcastRevokedPosition(User $operator, User $targetUser, UserPosition $currentAssignment): void
    {
        $currentAssignment->loadMissing('position.department');

        foreach ($this->chatState->getAllActiveRoomIds() as $roomId) {
            broadcast(new AppointmentAnnounced(
                roomId: $roomId,
                targetUsername: $targetUser->username,
                positionIcon: $currentAssignment->position?->icon ?? '🎖️',
                positionName: $currentAssignment->position?->name ?? '',
                departmentName: $currentAssignment->position?->department?->name ?? '',
                operatorName: $operator->username,
                type: 'revoke',
            ));
        }

        broadcast(new UserBrowserRefreshRequested(
            targetUserId: $targetUser->id,
            operator: $operator->username,
            reason: '你的职务已被撤销，页面权限正在同步更新。',
        ));
    }
}
