<?php

/**
 * 文件功能：好友系统控制器
 *
 * 处理聊天室内的好友关系管理：
 * 1. 添加好友（addFriend）
 * 2. 删除好友（removeFriend）
 * 3. 查询与指定用户的好友关系（status）
 * 4. 查询当前用户的好友列表（index）
 *
 * 好友关系模型：单向存储，互相添加才构成双向好友。
 * 使用原版 friend_requests 表（字段：who / towho / sub_time）。
 *
 * @author   ChatRoom Laravel
 *
 * @version  1.0.0
 */

namespace App\Http\Controllers;

use App\Events\FriendAdded;
use App\Events\FriendRemoved;
use App\Models\FriendRequest;
use App\Models\User;
use App\Services\ChatStateService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class FriendController extends Controller
{
    /**
     * 注入 Redis 状态服务，用于推送悄悄话通知。
     */
    public function __construct(
        private readonly ChatStateService $chatState,
    ) {}

    /**
     * 查询当前用户与目标用户的好友关系状态。
     *
     * 返回：
     *  - is_friend: 当前用户是否已将对方加为好友
     *  - mutual:    是否互相添加（双向好友）
     *
     * @param  string  $username  目标用户名
     */
    public function status(string $username): JsonResponse
    {
        $me = Auth::user();

        // 我是否已将对方加为好友
        $iAdded = FriendRequest::where('who', $me->username)
            ->where('towho', $username)
            ->exists();

        // 对方是否也将我加为好友
        $theyAdded = FriendRequest::where('who', $username)
            ->where('towho', $me->username)
            ->exists();

        return response()->json([
            'is_friend' => $iAdded,
            'mutual' => $iAdded && $theyAdded,
        ]);
    }

    /**
     * 添加好友。
     *
     * 流程：
     * 1. 校验目标用户存在、且不是自己
     * 2. 检查是否已经添加过
     * 3. 写入 friend_requests 记录
     * 4. 检查是否互相好友（B 是否已将 A 加为好友）
     * 5. 广播 FriendAdded 事件通知对方（携带互相状态）
     * 6. 若对方在线，向对方发送正确的悄悄话
     *
     * @param  string  $username  目标用户名
     */
    public function addFriend(Request $request, string $username): JsonResponse
    {
        $me = Auth::user();

        // 不能加自己
        if ($me->username === $username) {
            return response()->json(['status' => 'error', 'message' => '不能将自己加为好友'], 422);
        }

        // 检查目标用户是否存在
        $target = User::where('username', $username)->first();
        if (! $target) {
            return response()->json(['status' => 'error', 'message' => '用户不存在'], 404);
        }

        // 是否已添加
        $exists = FriendRequest::where('who', $me->username)->where('towho', $username)->exists();
        if ($exists) {
            return response()->json(['status' => 'error', 'message' => '已是好友，无需重复添加'], 422);
        }

        // 写入好友关系（A → B）
        FriendRequest::create([
            'who' => $me->username,
            'towho' => $username,
            'sub_time' => now(),
        ]);

        // 检查 B 是否已将 A 加为好友（互相好友判断）
        $hasAddedBack = FriendRequest::where('who', $username)
            ->where('towho', $me->username)
            ->exists();

        // 广播给对方（仅对方可见），携带是否已回加的状态；用数字 ID 作为频道名，避免中文名
        broadcast(new FriendAdded($me->username, $username, $target->id, $hasAddedBack));

        // 若对方在线，推送聊天区悄悄话（文案根据互相状态区分）
        $this->notifyOnlineUser($username, $me->username, 'added', $request->input('room_id'), $hasAddedBack);

        return response()->json([
            'status' => 'success',
            'message' => '已成功添加 '.$username.' 为好友 🎉',
        ]);
    }

    /**
     * 删除好友。
     *
     * 流程：
     * 1. 删除 friend_requests 中「我 → 对方」的记录
     * 2. 检查对方是否也将我加为好友（之前是否互相）
     * 3. 广播 FriendRemoved 事件通知对方
     * 4. 若对方在线，向对方发送悄悄话
     *
     * @param  string  $username  目标用户名
     */
    public function removeFriend(Request $request, string $username): JsonResponse
    {
        $me = Auth::user();

        $deleted = FriendRequest::where('who', $me->username)
            ->where('towho', $username)
            ->delete();

        if (! $deleted) {
            return response()->json(['status' => 'error', 'message' => '好友关系不存在'], 404);
        }

        // 检查 B 之前是否也将 A 加为好友（删除前的互相状态）
        $hadAddedBack = FriendRequest::where('who', $username)
            ->where('towho', $me->username)
            ->exists();

        // 查询目标用户 ID（用于私有频道，避免中文名非法）
        $targetUser = User::where('username', $username)->first();

        // 广播给对方，携带之前的互相好友状态；用数字 ID 避免中文频道名
        broadcast(new FriendRemoved($me->username, $username, $targetUser?->id ?? 0, $hadAddedBack));

        // 若对方在线，推送聊天区悄悄话（文案根据互相状态区分）
        $this->notifyOnlineUser($username, $me->username, 'removed', $request->input('room_id'), $hadAddedBack);

        return response()->json([
            'status' => 'success',
            'message' => '已将 '.$username.' 从好友列表移除',
        ]);
    }

    /**
     * 获取当前用户的完整好友数据，供好友面板使用。
     *
     * 返回两个列表：
     *  - friends：我已添加的好友（含互相状态、添加时间）
     *  - pending：对方已加我但我还未加对方的（含对方添加我的时间）
     */
    public function index(): JsonResponse
    {
        $me = Auth::user();

        // ── 我添加的好友及添加时间 ──
        $myRows = FriendRequest::where('who', $me->username)
            ->get(['towho', 'sub_time'])
            ->keyBy('towho');

        // ── 把我加了的人（用于互相判断 + pending 列表）──
        $addedMeRows = FriendRequest::where('towho', $me->username)
            ->get(['who', 'sub_time'])
            ->keyBy('who');

        $myAddedNames = $myRows->keys();
        $addedMeNames = $addedMeRows->keys();

        // ── 查询全局在线用户（所有房间合并）──
        $onlineUsernames = collect($this->chatState->getAllOnlineUsernames());

        // 我添加的好友详情
        $friends = User::whereIn('username', $myAddedNames)
            ->get(['username', 'usersf', 'user_level', 'sex'])
            ->map(function ($u) use ($myRows, $addedMeNames, $onlineUsernames) {
                $row = $myRows->get($u->username);

                return [
                    'username' => $u->username,
                    'headface' => $u->headface,
                    'user_level' => $u->user_level,
                    'sex' => $u->sex,
                    'mutual' => $addedMeNames->contains($u->username), // 是否互相添加
                    'sub_time' => $row?->sub_time?->format('Y-m-d H:i') ?? '',
                    'is_online' => $onlineUsernames->contains($u->username),
                ];
            })
            ->sortByDesc('is_online') // 在线好友排在前面
            ->values();

        // 对方加了我但我还未加的（pending）
        $pendingNames = $addedMeNames->diff($myAddedNames);
        $pending = User::whereIn('username', $pendingNames)
            ->get(['username', 'usersf', 'user_level', 'sex'])
            ->map(function ($u) use ($addedMeRows, $onlineUsernames) {
                $row = $addedMeRows->get($u->username);

                return [
                    'username' => $u->username,
                    'headface' => $u->headface,
                    'user_level' => $u->user_level,
                    'sex' => $u->sex,
                    'added_at' => $row?->sub_time?->format('Y-m-d H:i') ?? '',
                    'is_online' => $onlineUsernames->contains($u->username),
                ];
            })
            ->sortByDesc('is_online')
            ->values();

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

    /**
     * 若目标用户在线，向其发送系统悄悄话通知。
     *
     * 根据 $action 和 $mutual 显示不同文案，避免「你们已是好友」的误导提示。
     *
     * @param  string  $targetUsername  接收通知的用户名
     * @param  string  $fromUsername  发起操作的用户名
     * @param  string  $action  'added' | 'removed' | 'online'
     * @param  int|null  $roomId  当前房间 ID
     * @param  bool  $mutual  是否互相好友（added: B 是否已回加；removed: 之前是否互相）
     */
    private function notifyOnlineUser(
        string $targetUsername,
        string $fromUsername,
        string $action,
        ?int $roomId = null,
        bool $mutual = false,
    ): void {
        if (! $roomId) {
            return;
        }

        // 检查对方是否在该房间在线
        $onlineUsers = $this->chatState->getRoomUsers($roomId);
        if (! isset($onlineUsers[$targetUsername])) {
            return;
        }

        // 根据操作类型和互相状态生成不同文案（含前端代理快捷操作链接）
        $btnStyle = 'font-weight:bold;text-decoration:underline;margin-left:6px;';
        $safeUsername = e($fromUsername);
        $btnAdd = "<a href='#' data-quick-friend-action='add' data-quick-friend-username='{$safeUsername}' style='color:#16a34a;{$btnStyle}'>➕ 回加好友</a>";
        $btnRemove = "<a href='#' data-quick-friend-action='remove' data-quick-friend-username='{$safeUsername}' style='color:#6b7280;{$btnStyle}'>🗑️ 同步移除</a>";

        $content = match ($action) {
            'added' => $mutual
                ? "💚 <b>{$safeUsername}</b> 将你加为好友了！你们现在互为好友 🎉"
                : "💚 <b>{$safeUsername}</b> 将你加为好友了！但你还没有添加对方为好友。{$btnAdd}",
            'removed' => $mutual
                ? "💔 <b>{$safeUsername}</b> 已将你从好友列表移除。你的好友列表中仍保留对方。{$btnRemove}"
                : "💔 <b>{$safeUsername}</b> 已将你从他的好友列表移除。",
            'online' => "🟢 你的好友 <b>{$safeUsername}</b> 上线啦！",
            default => '',
        };

        if (! $content) {
            return;
        }

        // 删除相关用灰色，其他用绿色
        $fontColor = $action === 'removed' ? '#6b7280' : '#16a34a';

        // 构建系统悄悄话消息
        $msg = [
            'id' => $this->chatState->nextMessageId($roomId),
            'room_id' => $roomId,
            'from_user' => '系统',
            'to_user' => $targetUsername,
            'content' => $content,
            'is_secret' => true,
            'font_color' => $fontColor,
            'action' => '',
            'sent_at' => now()->toDateTimeString(),
        ];

        $this->chatState->pushMessage($roomId, $msg);
        broadcast(new \App\Events\MessageSent($roomId, $msg));
    }
}
