// 好友面板事件绑定与列表渲染，替代 Blade 内联脚本。

let friendPanelEventsBound = false;

/**
 * 获取当前房间 ID。
 *
 * @returns {number|null}
 */
function roomId() {
    return window.chatContext?.roomId ?? null;
}

/**
 * 获取 CSRF Token。
 *
 * @returns {string}
 */
function csrf() {
    return document.querySelector('meta[name="csrf-token"]')?.content ?? "";
}

/**
 * 在面板顶部显示操作结果提示文字。
 *
 * @param {string} message 提示文字
 * @param {string} color 文字颜色
 * @returns {void}
 */
function setNotice(message, color = "#888") {
    const notice = document.getElementById("fp-notice");
    if (!notice) {
        return;
    }

    notice.textContent = message;
    notice.style.color = color;
}

/**
 * 打开好友面板并自动拉取最新好友数据。
 *
 * @returns {void}
 */
export function openFriendPanel() {
    const panel = document.getElementById("friend-panel");
    if (!panel) {
        return;
    }

    panel.style.display = "flex";
    loadFriends();
}

/**
 * 关闭好友面板。
 *
 * @returns {void}
 */
export function closeFriendPanel() {
    const panel = document.getElementById("friend-panel");
    if (panel) {
        panel.style.display = "none";
    }
}

/**
 * 从服务端读取好友列表，接口返回 friends 与 pending 两组数据。
 *
 * @returns {void}
 */
export function loadFriends() {
    const body = document.getElementById("friend-panel-body");
    if (!body) {
        return;
    }

    body.innerHTML = '<div class="fp-empty">加载中…</div>';
    setNotice("");

    fetch("/friends", {
        headers: {
            Accept: "application/json",
            "X-CSRF-TOKEN": csrf(),
        },
    })
        .then((response) => response.json())
        .then((data) => renderFriends(data.friends || [], data.pending || []))
        .catch(() => {
            body.innerHTML = '<div class="fp-empty">加载失败，请重试</div>';
        });
}

/**
 * 渲染好友列表与待回加列表。
 *
 * @param {Array<Record<string, unknown>>} friends 我已添加的好友
 * @param {Array<Record<string, unknown>>} pending 对方已加我但我未回加的用户
 * @returns {void}
 */
function renderFriends(friends, pending) {
    const body = document.getElementById("friend-panel-body");
    if (!body) {
        return;
    }

    body.innerHTML = "";

    const friendTitle = document.createElement("div");
    friendTitle.className = "fp-section-title";
    friendTitle.textContent = `📋 我关注的好友（${friends.length}）`;
    body.appendChild(friendTitle);

    if (friends.length === 0) {
        appendEmpty(body, "还没有添加任何好友");
    } else {
        friends.forEach((friend) => body.appendChild(makeFriendRow(friend)));
    }

    const pendingTitle = document.createElement("div");
    pendingTitle.className = "fp-section-title";
    pendingTitle.style.marginTop = "10px";
    pendingTitle.textContent = `💌 对方已加我，待我回加（${pending.length}）`;
    body.appendChild(pendingTitle);

    if (pending.length === 0) {
        appendEmpty(body, "暂无");
    } else {
        pending.forEach((pendingUser) => body.appendChild(makePendingRow(pendingUser)));
    }
}

/**
 * 向容器追加空状态提示。
 *
 * @param {HTMLElement} container 父容器
 * @param {string} text 提示文字
 * @returns {void}
 */
function appendEmpty(container, text) {
    const empty = document.createElement("div");
    empty.className = "fp-empty";
    empty.textContent = text;
    container.appendChild(empty);
}

/**
 * 解析好友头像路径。
 *
 * @param {unknown} headface 头像字段
 * @returns {string}
 */
function resolveFriendAvatar(headface) {
    const avatar = String(headface || "1.gif");

    // 后端可能返回 storage 相对路径或头像文件名，这里统一转成可直接使用的图片地址。
    return avatar.startsWith("storage/") ? `/${avatar}` : `/images/headface/${avatar}`;
}

/**
 * 创建我关注的好友行。
 *
 * @param {Record<string, unknown>} friend 好友数据
 * @returns {HTMLElement}
 */
function makeFriendRow(friend) {
    const row = document.createElement("div");
    row.className = "fp-row";

    const username = String(friend.username || "");
    const avatar = document.createElement("img");
    avatar.className = "fp-avatar";
    avatar.src = resolveFriendAvatar(friend.headface);
    avatar.alt = username;

    const name = document.createElement("span");
    name.className = "fp-name";
    name.textContent = username;

    const status = document.createElement("span");
    status.className = `fp-status ${friend.is_online ? "fp-status-online" : "fp-status-offline"}`;
    status.textContent = friend.is_online ? "🟢 在线" : "⚫ 离线";

    const badge = document.createElement("span");
    badge.className = `fp-badge ${friend.mutual ? "fp-badge-mutual" : "fp-badge-onesided"}`;
    badge.textContent = friend.mutual ? "💚 互相好友" : "👤 单向关注";

    const date = document.createElement("span");
    date.className = "fp-date";
    date.textContent = String(friend.sub_time || "");

    const button = document.createElement("button");
    button.className = "fp-action-btn fp-btn-remove";
    button.textContent = "删除";
    // 好友行是接口返回后动态创建的，按钮监听直接挂在当前行元素上即可。
    button.addEventListener("click", () => {
        void friendAction("remove", username, button);
    });

    row.append(avatar, name, status, badge, date, button);
    return row;
}

/**
 * 创建待回加用户行。
 *
 * @param {Record<string, unknown>} pendingUser 待回加用户数据
 * @returns {HTMLElement}
 */
function makePendingRow(pendingUser) {
    const row = document.createElement("div");
    row.className = "fp-row";

    const username = String(pendingUser.username || "");
    const avatar = document.createElement("img");
    avatar.className = "fp-avatar";
    avatar.src = resolveFriendAvatar(pendingUser.headface);
    avatar.alt = username;

    const name = document.createElement("span");
    name.className = "fp-name";
    name.textContent = username;

    const status = document.createElement("span");
    status.className = `fp-status ${pendingUser.is_online ? "fp-status-online" : "fp-status-offline"}`;
    status.textContent = pendingUser.is_online ? "🟢 在线" : "⚫ 离线";

    const date = document.createElement("span");
    date.className = "fp-date";
    date.textContent = pendingUser.added_at ? `他于 ${pendingUser.added_at} 添加了我` : "";

    const button = document.createElement("button");
    button.className = "fp-action-btn fp-btn-add";
    button.textContent = "➕ 回加";
    button.addEventListener("click", () => {
        void friendAction("add", username, button);
    });

    row.append(avatar, name, status, date, button);
    return row;
}

/**
 * 添加或删除好友，与双击用户卡片复用同一组后端接口。
 *
 * @param {"add"|"remove"} action 操作类型
 * @param {string} username 目标用户名
 * @param {HTMLButtonElement} button 触发按钮
 * @returns {Promise<void>}
 */
async function friendAction(action, username, button) {
    button.disabled = true;
    button.style.opacity = "0.5";
    setNotice("");

    try {
        // 用户名进入 URL path 前必须编码，避免特殊字符破坏路径或请求目标。
        const response = await fetch(`/friend/${encodeURIComponent(username)}/${action}`, {
            method: action === "remove" ? "DELETE" : "POST",
            headers: {
                "X-CSRF-TOKEN": csrf(),
                "Content-Type": "application/json",
                Accept: "application/json",
            },
            body: JSON.stringify({
                // 房间 ID 用于后端生成房间内通知或校验上下文，不参与前端判权。
                room_id: roomId(),
            }),
        });
        const data = await response.json();

        if (data.status === "success") {
            setNotice(data.message, "#16a34a");
            // 延迟刷新，等待后端好友状态和通知链路落定。
            setTimeout(loadFriends, 700);
            return;
        }

        setNotice(data.message || "操作失败", "#dc2626");
        button.disabled = false;
        button.style.opacity = "1";
    } catch (error) {
        setNotice("网络异常，请重试", "#dc2626");
        button.disabled = false;
        button.style.opacity = "1";
    }
}

/**
 * 聊天消息和横幅内的快捷好友操作。
 *
 * @param {"add"|"remove"|string} action 操作类型
 * @param {string} username 目标用户名
 * @param {HTMLElement} element 触发元素
 * @returns {Promise<void>}
 */
export async function quickFriendAction(action, username, element) {
    if (!["add", "remove"].includes(action) || !username || !(element instanceof HTMLElement)) {
        return;
    }

    if (element.dataset.done) {
        return;
    }

    element.dataset.done = "1";
    element.textContent = "处理中…";
    element.style.pointerEvents = "none";

    try {
        // 消息内链接来自后端 HTML，用户名进入 path 前仍必须编码。
        const response = await fetch(`/friend/${encodeURIComponent(username)}/${action}`, {
            method: action === "add" ? "POST" : "DELETE",
            headers: {
                "Content-Type": "application/json",
                "X-CSRF-TOKEN": csrf(),
                Accept: "application/json",
            },
            body: JSON.stringify({
                room_id: roomId(),
            }),
        });
        const data = await response.json();

        if (data.status === "success") {
            element.textContent = action === "add" ? "✅ 已回加" : "✅ 已移除";
            element.style.color = "#16a34a";
            element.style.textDecoration = "none";
            return;
        }

        element.textContent = `❌ ${data.message || "操作失败"}`;
        element.style.color = "#cc4444";
    } catch (error) {
        element.textContent = "❌ 网络错误";
        element.style.color = "#cc4444";
        delete element.dataset.done;
        element.style.pointerEvents = "";
    }
}

/**
 * 通过搜索框按用户名添加好友，具体校验仍交给后端。
 *
 * @returns {Promise<void>}
 */
export async function friendSearch() {
    const input = document.getElementById("friend-search-input");
    if (!(input instanceof HTMLInputElement)) {
        return;
    }

    const username = input.value.trim();
    if (!username) {
        setNotice("请输入用户名", "#b45309");
        return;
    }

    const button = document.getElementById("friend-search-btn");
    if (!(button instanceof HTMLButtonElement)) {
        return;
    }

    button.disabled = true;
    setNotice("正在添加…");

    try {
        // 搜索输入的用户名同样先做 path 编码，再交由后端做存在性与权限校验。
        const response = await fetch(`/friend/${encodeURIComponent(username)}/add`, {
            method: "POST",
            headers: {
                "X-CSRF-TOKEN": csrf(),
                "Content-Type": "application/json",
                Accept: "application/json",
            },
            body: JSON.stringify({
                // 搜索添加也带上当前房间，保持和用户卡片添加好友入口一致。
                room_id: roomId(),
            }),
        });
        const data = await response.json();

        if (data.status === "success") {
            setNotice(data.message, "#16a34a");
            input.value = "";
            // 延迟刷新，等待后端好友状态和通知链路落定。
            setTimeout(loadFriends, 700);
        } else {
            setNotice(data.message || "添加失败", "#dc2626");
        }
    } catch (error) {
        setNotice("网络异常", "#dc2626");
    } finally {
        button.disabled = false;
    }
}

/**
 * 绑定好友面板关闭、遮罩关闭与搜索入口事件。
 *
 * @returns {void}
 */
export function bindFriendPanelControls() {
    if (friendPanelEventsBound || typeof document === "undefined") {
        return;
    }

    friendPanelEventsBound = true;
    document.addEventListener("click", (event) => {
        if (!(event.target instanceof Element)) {
            return;
        }

        if (event.target.closest("[data-friend-panel-close]")) {
            event.preventDefault();
            closeFriendPanel();
            return;
        }

        if (event.target.closest("[data-friend-search]")) {
            event.preventDefault();
            void friendSearch();
            return;
        }

        const quickAction = event.target.closest("[data-quick-friend-action]");
        if (quickAction) {
            event.preventDefault();
            // 后端系统消息只输出 data 属性，具体请求仍统一走模块方法。
            void quickFriendAction(
                quickAction.getAttribute("data-quick-friend-action") || "",
                quickAction.getAttribute("data-quick-friend-username") || "",
                quickAction,
            );
            return;
        }

        const panel = event.target.closest("#friend-panel");
        // 只在点击遮罩本身时关闭，避免点击内容区误关。
        if (panel && event.target === panel) {
            closeFriendPanel();
        }
    });

    document.addEventListener("keydown", (event) => {
        if (event.key !== "Enter" || event.target?.id !== "friend-search-input") {
            return;
        }

        event.preventDefault();
        void friendSearch();
    });
}
