// 聊天室钓鱼小游戏模块，管理抛竿、收竿、自动钓鱼循环和浮漂交互。

import { escapeHtml } from "./html.js";

let fishingEventsBound = false;
let fishingTimer = null;
let fishingReelTimeout = null;
let fishToken = null;
let autoFishing = false;
let autoFishCooldownTimer = null;
let autoFishCooldownCountdown = null;
let fishingCastPending = false;
const FISHING_MESSAGE_META_FONT_SIZE = "0.78em";
const FISHING_MESSAGE_BODY_FONT_SIZE = "1em";

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

/**
 * 获取私聊消息容器，钓鱼提示沿用旧版展示位置。
 *
 * @returns {HTMLElement|null}
 */
function messageContainer() {
    return document.getElementById("chat-messages-container2");
}

/**
 * 判断当前是否允许自动滚动。
 *
 * @returns {boolean}
 */
function shouldAutoScroll() {
    return typeof window.isChatAutoScrollEnabled === "function" ? window.isChatAutoScrollEnabled() : true;
}

/**
 * 追加一条钓鱼提示消息。
 *
 * @param {string} html
 * @returns {void}
 */
function appendFishingMessage(html) {
    const container = messageContainer();
    if (!container) {
        return;
    }

    const line = document.createElement("div");
    line.className = "msg-line";
    line.innerHTML = html;
    container.appendChild(line);

    if (shouldAutoScroll()) {
        container.scrollTop = container.scrollHeight;
    }
}

/**
 * 当前本地时间文本。
 *
 * @returns {string}
 */
function timeText() {
    return new Date().toLocaleTimeString("zh-CN", { hour12: false });
}

/**
 * 注入浮漂和自动钓鱼按钮需要的动画样式。
 *
 * @returns {void}
 */
function ensureFishingStyles() {
    if (!document.getElementById("bobber-style")) {
        const style = document.createElement("style");
        style.id = "bobber-style";
        style.textContent = `
            @keyframes bobberFloat {
                0%,100% { transform: translateY(0) rotate(-8deg); }
                50%      { transform: translateY(-10px) rotate(8deg); }
            }
            @keyframes bobberSink {
                0%   { transform: translateY(0) scale(1); opacity:1; }
                30%  { transform: translateY(12px) scale(1.3); opacity:1; }
                100% { transform: translateY(40px) scale(0.5); opacity:0; }
            }
            #fishing-bobber.sinking {
                animation: bobberSink 1.5s forwards !important;
            }
        `;
        document.head.appendChild(style);
    }

    if (!document.getElementById("auto-fish-stop-style")) {
        const style = document.createElement("style");
        style.id = "auto-fish-stop-style";
        style.textContent = `
            @keyframes autoFishBtnPulse {
                0%,100% { box-shadow: 0 4px 12px rgba(220,38,38,0.4); }
                50%      { box-shadow: 0 4px 20px rgba(220,38,38,0.7); }
            }
            #auto-fish-stop-btn {
                position: fixed;
                z-index: 10000;
                background: linear-gradient(135deg, #dc2626, #b91c1c);
                color: #fff;
                border: none;
                border-radius: 20px;
                padding: 8px 18px;
                font-size: 13px;
                font-weight: bold;
                cursor: grab;
                user-select: none;
                animation: autoFishBtnPulse 1.8s ease-in-out infinite;
                touch-action: none;
            }
            #auto-fish-stop-btn:active { cursor: grabbing; }
            #auto-fish-stop-btn .drag-hint {
                display: block;
                font-size: 9px;
                font-weight: normal;
                opacity: .65;
                margin-top: 1px;
                text-align: center;
                letter-spacing: .5px;
            }
        `;
        document.head.appendChild(style);
    }
}

/**
 * 创建浮漂 DOM 元素。
 *
 * @param {number} x 水平百分比
 * @param {number} y 垂直百分比
 * @returns {HTMLElement}
 */
export function createBobber(x, y) {
    ensureFishingStyles();

    const bobber = document.createElement("div");
    bobber.id = "fishing-bobber";
    bobber.style.cssText = `
        position: fixed;
        left: ${Number(x) || 50}vw;
        top: ${Number(y) || 50}vh;
        font-size: 28px;
        cursor: pointer;
        z-index: 9999;
        animation: bobberFloat 1.2s ease-in-out infinite;
        filter: drop-shadow(0 2px 6px rgba(0,0,0,0.4));
        user-select: none;
        transition: transform 0.3s;
    `;
    bobber.textContent = "🪝";
    bobber.title = "鱼上钩了！快点击！";

    return bobber;
}

/**
 * 移除当前浮漂。
 *
 * @returns {void}
 */
export function removeBobber() {
    document.getElementById("fishing-bobber")?.remove();
}

/**
 * 获取钓鱼按钮。
 *
 * @returns {HTMLButtonElement|null}
 */
function fishingButton() {
    const button = document.getElementById("fishing-btn");

    return button instanceof HTMLButtonElement ? button : null;
}

/**
 * 设置钓鱼按钮文案和禁用状态。
 *
 * @param {string} text
 * @param {boolean} disabled
 * @returns {void}
 */
function setFishingButton(text, disabled) {
    const button = fishingButton();
    if (!button) {
        return;
    }

    button.textContent = text;
    button.disabled = disabled;
}

/**
 * 判断当前是否已有进行中的钓鱼会话。
 *
 * 说明：
 * - 手动点击抛竿后，在等待浮漂、等待点击、等待自动收竿期间都视为会话未结束。
 * - 购买自动钓鱼卡后的自动接管，也必须避开这些中间态，避免重复抛竿。
 *
 * @returns {boolean}
 */
function hasActiveFishingSession() {
    return Boolean(
        fishingCastPending ||
        fishToken ||
        fishingTimer ||
        fishingReelTimeout ||
        document.getElementById("fishing-bobber"),
    );
}

/**
 * 启动自动钓鱼冷却倒计时（基于时间戳，不受浏览器后台节流影响）。
 *
 * @param {number} cooldown 冷却秒数
 * @returns {void}
 */
function startAutoFishingCooldown(cooldown) {
    clearAutoFishingTimers();

    const endTime = Date.now() + cooldown * 1000;
    setFishingButton(`⏳ 冷却 ${cooldown}s`, true);
    showAutoFishStopButton(cooldown);

    // 基于时间戳更新倒计时 UI — 后台节流后回来也能准确显示
    autoFishCooldownCountdown = window.setInterval(() => {
        const remaining = Math.max(0, Math.ceil((endTime - Date.now()) / 1000));
        setFishingButton(`⏳ 冷却 ${remaining}s`, true);
        updateAutoFishStopButtonCountdown(remaining);

        if (remaining <= 0) {
            window.clearInterval(autoFishCooldownCountdown);
            autoFishCooldownCountdown = null;
        }
    }, 200);

    // 基于时间戳检测冷却结束 — 后台节流后立即触发
    autoFishCooldownTimer = null;
    const checkEnd = () => {
        if (Date.now() >= endTime) {
            autoFishCooldownTimer = null;
            if (autoFishing) {
                updateAutoFishStopButtonCountdown(0, "正在继续自动钓鱼");
                void startFishing();
                return;
            }

            hideAutoFishStopButton();
            return;
        }
        autoFishCooldownTimer = window.setTimeout(checkEnd, 200);
    };
    autoFishCooldownTimer = window.setTimeout(checkEnd, Math.min(cooldown * 1000, 200));
}

/**
 * 展示可拖动的停止自动钓鱼按钮。
 *
 * @param {number} cooldown
 * @returns {void}
 */
function showAutoFishStopButton(cooldown) {
    const currentButton = document.getElementById("auto-fish-stop-btn");
    if (currentButton) {
        updateAutoFishStopButtonCountdown(cooldown);
        return;
    }

    ensureFishingStyles();

    const button = document.createElement("button");
    button.id = "auto-fish-stop-btn";
    button.innerHTML = `🛑 停止自动钓鱼<span class="drag-hint">冷却 ${Number(cooldown) || 0}s · 可拖动</span>`;

    try {
        const saved = JSON.parse(window.localStorage.getItem("autoFishBtnPos") || "null");
        if (saved) {
            button.style.left = `${Number(saved.left) || 0}px`;
            button.style.top = `${Number(saved.top) || 0}px`;
        } else {
            button.style.bottom = "80px";
            button.style.right = "20px";
        }
    } catch (error) {
        button.style.bottom = "80px";
        button.style.right = "20px";
    }

    bindAutoFishStopDrag(button);
    document.body.appendChild(button);
}

/**
 * 同步更新停止自动钓鱼浮层上的冷却秒数，避免与主按钮倒计时不一致。
 *
 * @param {number} cooldown
 * @param {string|null} text
 * @returns {void}
 */
function updateAutoFishStopButtonCountdown(cooldown, text = null) {
    const hint = document.querySelector("#auto-fish-stop-btn .drag-hint");

    if (!(hint instanceof HTMLElement)) {
        return;
    }

    hint.textContent = text || `冷却 ${Number(cooldown) || 0}s · 可拖动`;
}

/**
 * 给停止自动钓鱼按钮绑定拖拽和点击停止事件。
 *
 * @param {HTMLButtonElement} button
 * @returns {void}
 */
function bindAutoFishStopDrag(button) {
    let isDragging = false;
    let startX = 0;
    let startY = 0;
    let startLeft = 0;
    let startTop = 0;

    const dragStart = (event) => {
        const rect = button.getBoundingClientRect();
        button.style.left = `${rect.left}px`;
        button.style.top = `${rect.top}px`;
        button.style.right = "auto";
        button.style.bottom = "auto";

        isDragging = false;
        const point = event.touches ? event.touches[0] : event;
        startX = point.clientX;
        startY = point.clientY;
        startLeft = rect.left;
        startTop = rect.top;

        document.addEventListener("mousemove", dragMove, { passive: false });
        document.addEventListener("mouseup", dragEnd);
        document.addEventListener("touchmove", dragMove, { passive: false });
        document.addEventListener("touchend", dragEnd);
    };

    const dragMove = (event) => {
        event.preventDefault();
        const point = event.touches ? event.touches[0] : event;
        const dx = point.clientX - startX;
        const dy = point.clientY - startY;

        if (Math.abs(dx) > 3 || Math.abs(dy) > 3) {
            isDragging = true;
        }

        if (!isDragging) {
            return;
        }

        const nextLeft = Math.max(0, Math.min(window.innerWidth - button.offsetWidth, startLeft + dx));
        const nextTop = Math.max(0, Math.min(window.innerHeight - button.offsetHeight, startTop + dy));
        button.style.left = `${nextLeft}px`;
        button.style.top = `${nextTop}px`;
    };

    const dragEnd = () => {
        document.removeEventListener("mousemove", dragMove);
        document.removeEventListener("mouseup", dragEnd);
        document.removeEventListener("touchmove", dragMove);
        document.removeEventListener("touchend", dragEnd);

        if (isDragging) {
            window.localStorage.setItem("autoFishBtnPos", JSON.stringify({
                left: Number.parseInt(button.style.left, 10),
                top: Number.parseInt(button.style.top, 10),
            }));
        }
    };

    button.addEventListener("mousedown", dragStart);
    button.addEventListener("touchstart", dragStart, { passive: true });
    button.addEventListener("click", () => {
        if (!isDragging) {
            stopAutoFishing();
        }
    });
}

/**
 * 隐藏停止自动钓鱼按钮。
 *
 * @returns {void}
 */
function hideAutoFishStopButton() {
    document.getElementById("auto-fish-stop-btn")?.remove();
}

/**
 * 开始钓鱼：调用抛竿接口并显示浮漂。
 *
 * @returns {Promise<void>}
 */
export async function startFishing() {
    if (hasActiveFishingSession()) {
        return;
    }

    fishingCastPending = true;
    setFishingButton("🎣 抛竿中...", true);

    try {
        const response = await fetch(window.chatContext.fishCastUrl, {
            method: "POST",
            headers: {
                "X-CSRF-TOKEN": csrf(),
                "Accept": "application/json",
            },
        });
        const data = await response.json();

        if (!response.ok || data.status !== "success") {
            if (autoFishing && response.status === 429) {
                // 服务端冷却 TTL 可能与前端倒计时有毫秒级误差，自动模式下按服务端剩余时间续等。
                startAutoFishingCooldown(Math.max(1, Number(data.cooldown) || 1));
                return;
            }

            if (autoFishing && response.status === 409) {
                // 多标签页或重复自动抛竿时，后端会保留先到的 token，当前页等待后再接管。
                appendFishingMessage(`<span style="color:#d97706;">【钓鱼】${escapeHtml(data.message || "已有钓鱼正在进行，稍后自动重试。")}</span><span class="msg-time">(${timeText()})</span>`);
                startAutoFishingCooldown(Math.max(1, Number(data.retry_after) || 5));
                return;
            }

            window.chatDialog?.alert?.(data.message || "钓鱼失败", "操作失败", "#cc4444");
            setFishingButton("🎣 钓鱼", false);
            return;
        }

        // 抛竿成功后进入正式钓鱼会话，由 token / timer 接管后续状态。
        fishToken = data.token;
        autoFishing = Boolean(data.auto_fishing);
        appendFishingMessage(`<span style="color:#2563eb;font-weight:bold;">🎣【钓鱼】</span>${escapeHtml(data.message)}<span class="msg-time">(${timeText()})</span>`);
        setFishingButton("🎣 等待中...", true);

        const bobber = createBobber(data.bobber_x, data.bobber_y);
        document.body.appendChild(bobber);

        if (data.auto_fishing) {
            showAutoFishStopButton(0);
            updateAutoFishStopButtonCountdown(0, "等待鱼儿上钩 · 可拖动");
        }

        fishingTimer = window.setTimeout(() => {
            // 等待计时器触发后必须立即释放句柄，否则自动钓鱼冷却结束会误判仍有会话进行中。
            fishingTimer = null;
            bobber.classList.add("sinking");
            bobber.textContent = "🐟";

            if (data.auto_fishing) {
                showAutoFishStopButton(0);
                updateAutoFishStopButtonCountdown(0, "自动收竿中 · 可拖动");
                appendFishingMessage(`<span style="color:#7c3aed;font-weight:bold;">🎣 自动钓鱼卡生效！自动收竿中... <span style="font-size:${FISHING_MESSAGE_META_FONT_SIZE};opacity:0.7">（剩余${Number(data.auto_fishing_minutes_left) || 0}分钟）</span></span>`);
                fishingReelTimeout = window.setTimeout(() => {
                    removeBobber();
                    void reelFish();
                }, 1800);
                return;
            }

            appendFishingMessage(`<span style="color:#d97706;font-weight:bold;font-size:${FISHING_MESSAGE_BODY_FONT_SIZE};">🐟 鱼上钩了！快点击屏幕上的浮漂！</span>`);
            setFishingButton("🎣 点击浮漂！", true);
            bobber.addEventListener("click", () => {
                removeBobber();

                if (fishingReelTimeout) {
                    window.clearTimeout(fishingReelTimeout);
                    fishingReelTimeout = null;
                }

                void reelFish();
            }, { once: true });

            fishingReelTimeout = window.setTimeout(() => {
                removeBobber();
                fishToken = null;
                appendFishingMessage('<span style="color:#999;">💨 你反应太慢了，鱼跑掉了...</span>');
                resetFishingBtn();
            }, 8000);
        }, Number(data.wait_time || 0) * 1000);
    } catch (error) {
        window.chatDialog?.alert?.(`网络错误：${error.message}`, "网络异常", "#cc4444");
        removeBobber();
        setFishingButton("🎣 钓鱼", false);
    } finally {
        fishingCastPending = false;
    }
}

/**
 * 收竿并提交本次钓鱼 token。
 *
 * @returns {Promise<void>}
 */
export async function reelFish() {
    setFishingButton("🎣 拉竿中...", true);

    if (fishingReelTimeout) {
        window.clearTimeout(fishingReelTimeout);
        fishingReelTimeout = null;
    }

    const token = fishToken;
    fishToken = null;

    try {
        const response = await fetch(window.chatContext.fishReelUrl, {
            method: "POST",
            headers: {
                "X-CSRF-TOKEN": csrf(),
                "Accept": "application/json",
                "Content-Type": "application/json",
            },
            body: JSON.stringify({ token }),
        });
        const data = await response.json();

        if (response.ok && data.status === "success") {
            const result = data.result || {};
            const color = Number(result.exp || 0) >= 0 ? "#16a34a" : "#dc2626";
            appendFishingMessage(
                `<span style="color:${color};font-weight:bold;">${escapeHtml(result.emoji || "🎣")}【钓鱼结果】</span>${escapeHtml(result.message || "")}` +
                ` <span style="color:#666;font-size:${FISHING_MESSAGE_META_FONT_SIZE};">（经验:${Number(data.exp_num) || 0} 金币:${Number(data.jjb) || 0}）</span>` +
                `<span class="msg-time">(${timeText()})</span>`,
            );

            if (autoFishing) {
                startAutoFishingCooldown(Number(data.cooldown_seconds) || 300);
                return;
            }
        } else {
            appendFishingMessage(`<span style="color:red;">【钓鱼】${escapeHtml(data.message || "操作失败")}</span><span class="msg-time">(${timeText()})</span>`);

            if (autoFishing) {
                retryAutoFishing();
                return;
            }

            autoFishing = false;
        }
    } catch (error) {
        if (autoFishing) {
            appendFishingMessage('<span style="color:#d97706;">⚠️ 网络异常，5秒后自动重试钓鱼...</span>');
            retryAutoFishing();
            return;
        }

        window.chatDialog?.alert?.(`网络错误：${error.message}`, "网络异常", "#cc4444");
        autoFishing = false;
    }

    resetFishingBtn();
}

/**
 * 自动钓鱼异常时短暂等待后重试。
 *
 * @returns {void}
 */
function retryAutoFishing() {
    setFishingButton("⏳ 重试中...", true);
    autoFishCooldownTimer = window.setTimeout(() => {
        autoFishCooldownTimer = null;

        if (autoFishing) {
            void startFishing();
        }
    }, 5000);
}

/**
 * 手动停止自动钓鱼循环。
 *
 * @returns {void}
 */
export function stopAutoFishing() {
    autoFishing = false;
    clearAutoFishingTimers();
    hideAutoFishStopButton();
    appendFishingMessage('<span style="color:#6b7280;">🛑 已停止自动钓鱼。</span>');
    resetFishingBtn();
}

/**
 * 清理自动钓鱼冷却计时器。
 *
 * @returns {void}
 */
function clearAutoFishingTimers() {
    if (autoFishCooldownTimer) {
        window.clearTimeout(autoFishCooldownTimer);
        autoFishCooldownTimer = null;
    }

    if (autoFishCooldownCountdown) {
        window.clearInterval(autoFishCooldownCountdown);
        autoFishCooldownCountdown = null;
    }
}

/**
 * 重置钓鱼按钮和临时状态。
 *
 * @returns {void}
 */
export function resetFishingBtn() {
    autoFishing = false;
    fishingCastPending = false;
    clearAutoFishingTimers();
    hideAutoFishStopButton();

    if (fishingTimer) {
        window.clearTimeout(fishingTimer);
        fishingTimer = null;
    }

    if (fishingReelTimeout) {
        window.clearTimeout(fishingReelTimeout);
        fishingReelTimeout = null;
    }

    setFishingButton("🎣 钓鱼", false);
    removeBobber();
}

/**
 * 检查自动钓鱼卡状态并恢复自动循环。
 *
 * @returns {void}
 */
export function checkAndAutoStartFishing() {
    const minutesLeft = Number(window.chatContext?.autoFishingMinutesLeft || 0);
    const initialCooldown = Number(window.chatContext?.fishingCooldownSeconds || 0);

    if (minutesLeft <= 0 || autoFishing || hasActiveFishingSession()) {
        return;
    }

    autoFishing = true;

    if (initialCooldown > 0) {
        console.log(`检测到自动钓鱼卡有效，恢复钓鱼状态，剩余冷却 ${initialCooldown}s`);
        startAutoFishingCooldown(initialCooldown);
        return;
    }

    console.log("检测到自动钓鱼卡有效，自动抛竿");
    void startFishing();
}

/**
 * 绑定钓鱼按钮、全局兼容入口和清屏恢复事件。
 *
 * @returns {void}
 */
export function bindFishingControls() {
    if (typeof window === "undefined") {
        return;
    }

    window.createBobber = createBobber;
    window.removeBobber = removeBobber;
    window.startFishing = startFishing;
    window.reelFish = reelFish;
    window.stopAutoFishing = stopAutoFishing;
    window.resetFishingBtn = resetFishingBtn;
    window.checkAndAutoStartFishing = checkAndAutoStartFishing;

    if (fishingEventsBound || typeof document === "undefined") {
        return;
    }

    fishingEventsBound = true;
    document.addEventListener("click", (event) => {
        if (!(event.target instanceof Element) || !event.target.closest("[data-chat-fishing-start]")) {
            return;
        }

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

    document.addEventListener("DOMContentLoaded", () => {
        checkAndAutoStartFishing();
        window.addEventListener("chat:screen-cleared", () => {
            if (!autoFishing) {
                checkAndAutoStartFishing();
            }
        });
    });
}
