// 赛马竞猜主面板 Alpine 组件，负责当前场次、下注、跑马进度和结算展示。

const DEFAULT_HORSE_RACE_CURRENT_URL = "/horse-race/current";
const DEFAULT_HORSE_RACE_BET_URL = "/horse-race/bet";
const DEFAULT_HORSE_RACE_HISTORY_URL = "/horse-race/history";
const DEFAULT_HORSE_RACE_MIN_BET = 100;
const DEFAULT_HORSE_RACE_MAX_BET = 100000;
const DEFAULT_HORSE_RACE_TOTAL_SECONDS = 90;
const SETTLED_AUTO_CLOSE_SECONDS = 10;

/**
 * 读取赛马接口地址，优先使用 Blade 写入的命名路由。
 *
 * @returns {{current: string, bet: string, history: string}}
 */
function horseRaceUrls() {
    const panel = document.getElementById("horse-race-panel");

    return {
        current: panel?.dataset.horseRaceCurrentUrl || DEFAULT_HORSE_RACE_CURRENT_URL,
        bet: panel?.dataset.horseRaceBetUrl || DEFAULT_HORSE_RACE_BET_URL,
        history: panel?.dataset.horseRaceHistoryUrl || DEFAULT_HORSE_RACE_HISTORY_URL,
    };
}

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

/**
 * 生成快捷下注金额，保持固定 5 档按钮稳定渲染。
 *
 * @param {number} min 最小下注额
 * @param {number} max 最大下注额
 * @returns {number[]}
 */
function buildQuickBetAmounts(min, max) {
    const candidates = [1, 2, 5, 10, 20, 50, 100, 200, 500, 1000];
    const steps = candidates
        .map((multiplier) => min * multiplier)
        .filter((value) => value >= min && value < max);
    let sortedSteps = [...new Set([...steps, max])].sort((a, b) => a - b);

    if (sortedSteps.length >= 5) {
        return [
            sortedSteps[0],
            sortedSteps[Math.floor((sortedSteps.length - 1) * 0.25)],
            sortedSteps[Math.floor((sortedSteps.length - 1) * 0.5)],
            sortedSteps[Math.floor((sortedSteps.length - 1) * 0.75)],
            sortedSteps[sortedSteps.length - 1],
        ];
    }

    // 下注范围很小时补齐中间档位，避免按钮数量变化造成布局跳动。
    while (sortedSteps.length < 5) {
        let maxGap = 0;
        let insertIndex = -1;

        for (let index = 0; index < sortedSteps.length - 1; index += 1) {
            if (sortedSteps[index + 1] - sortedSteps[index] > maxGap) {
                maxGap = sortedSteps[index + 1] - sortedSteps[index];
                insertIndex = index;
            }
        }

        if (insertIndex === -1) {
            break;
        }

        let newValue = Math.floor((sortedSteps[insertIndex] + sortedSteps[insertIndex + 1]) / 2);
        if (newValue > 100) {
            newValue = Math.floor(newValue / 10) * 10;
        }
        sortedSteps.splice(insertIndex + 1, 0, newValue);
    }

    return sortedSteps;
}

/**
 * 读取赛马接口 JSON；若后端返回 HTML/警告页，则抛出可诊断错误。
 *
 * @param {string} url 请求地址
 * @param {RequestInit} options fetch 选项
 * @returns {Promise<any>}
 */
export async function requestHorseRaceJson(url, options = {}) {
    const requestUrl = new URL(url, window.location.origin);
    requestUrl.searchParams.set("_ts", Date.now().toString());

    const response = await fetch(requestUrl.toString(), {
        cache: "no-store",
        headers: {
            Accept: "application/json",
            "Cache-Control": "no-cache",
            Pragma: "no-cache",
            ...(options.headers || {}),
        },
        ...options,
    });
    const rawText = await response.text();

    try {
        return JSON.parse(rawText);
    } catch (error) {
        const preview = rawText.slice(0, 160).replace(/\s+/g, " ").trim();
        throw new Error(`赛马接口未返回 JSON（${response.status}）: ${preview}`);
    }
}

/**
 * 创建赛马竞猜主面板 Alpine 组件。
 *
 * @returns {Record<string, any>}
 */
export function horseRacePanel() {
    return {
        show: false,
        phase: "idle",
        raceId: null,
        totalSeconds: DEFAULT_HORSE_RACE_TOTAL_SECONDS,
        countdown: DEFAULT_HORSE_RACE_TOTAL_SECONDS,
        countdownTimer: null,
        settledCountdown: SETTLED_AUTO_CLOSE_SECONDS,
        settledTimer: null,
        horses: [],
        positions: {},
        leaderId: null,
        totalPool: 0,
        myBet: false,
        myBetHorseId: null,
        myBetHorseName: "",
        myBetAmount: 0,
        selectedHorse: null,
        betAmount: DEFAULT_HORSE_RACE_MIN_BET,
        minBet: DEFAULT_HORSE_RACE_MIN_BET,
        maxBet: DEFAULT_HORSE_RACE_MAX_BET,
        submitting: false,
        winnerName: "",
        winnerEmoji: "",
        myWon: false,
        myPayout: 0,
        history: [],

        /**
         * 兼容事件模块调用的 JSON 请求入口。
         *
         * @param {string} url 请求地址
         * @param {RequestInit} options fetch 选项
         * @returns {Promise<any>}
         */
        requestJson(url, options = {}) {
            return requestHorseRaceJson(url, options);
        },

        /**
         * 同步全局聊天上下文中的金币余额，供弹窗右上角与其他面板共用。
         *
         * @param {number|string|null|undefined} jjb 最新金币余额
         * @returns {void}
         */
        syncUserGold(jjb) {
            if (jjb === undefined || jjb === null || !window.chatContext) {
                return;
            }

            window.chatContext.userJjb = Number(jjb);
            window.chatContext.myGold = Number(jjb);
        },

        /**
         * 获取当前选中马匹的预览名称。
         *
         * @returns {string}
         */
        get myBetHorsePreviewName() {
            if (!this.selectedHorse) {
                return "";
            }

            const horse = this.horses.find((item) => item.id === this.selectedHorse);
            return horse ? `${horse.emoji}${horse.name}` : "";
        },

        /**
         * 获取快捷下注金额数组。
         *
         * @returns {number[]}
         */
        get quickBetAmounts() {
            return buildQuickBetAmounts(this.minBet || DEFAULT_HORSE_RACE_MIN_BET, this.maxBet || DEFAULT_HORSE_RACE_MAX_BET);
        },

        /**
         * 开赛：填充场次数据并开始倒计时。
         *
         * @param {Record<string, any>} data 开赛广播数据
         * @returns {void}
         */
        openRace(data) {
            this.phase = "betting";
            this.raceId = data.race_id;
            this.countdown = data.bet_seconds || DEFAULT_HORSE_RACE_TOTAL_SECONDS;
            this.totalSeconds = this.countdown;
            this.horses = data.horses || [];
            this.totalPool = data.total_pool || 0;
            this.myBet = false;
            this.myBetHorseId = null;
            this.myBetHorseName = "";
            this.myBetAmount = 0;
            this.selectedHorse = null;
            this.betAmount = this.minBet || DEFAULT_HORSE_RACE_MIN_BET;
            this.positions = {};
            this.leaderId = null;
            this.show = true;

            this.loadCurrentRace();
            this.startCountdown();
            this.updateFab(true);
        },

        /**
         * 从接口获取当前场次状态，包括本人下注、注池和赔率。
         *
         * @returns {Promise<void>}
         */
        async loadCurrentRace() {
            try {
                const data = await this.requestJson(horseRaceUrls().current);
                this.syncUserGold(data.jjb);

                if (data.race) {
                    this.applyRaceState(data.race);
                    return;
                }

                this.resetToIdleState();
            } catch (error) {
                // 当前场次刷新失败不弹窗，避免影响用户关闭或查看面板。
            }
        },

        /**
         * 启动下注倒计时。
         *
         * @returns {void}
         */
        startCountdown() {
            clearInterval(this.countdownTimer);
            this.countdownTimer = setInterval(() => {
                this.countdown -= 1;
                if (this.countdown <= 0) {
                    clearInterval(this.countdownTimer);
                    this.countdownTimer = null;
                    this.phase = "running";
                }
            }, 1000);
        },

        /**
         * 提交本场下注。
         *
         * @returns {Promise<void>}
         */
        async submitBet() {
            if (!this.selectedHorse || this.betAmount < DEFAULT_HORSE_RACE_MIN_BET || this.submitting) {
                return;
            }

            this.submitting = true;

            try {
                const response = await fetch(horseRaceUrls().bet, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        Accept: "application/json",
                        "X-CSRF-TOKEN": csrfToken(),
                    },
                    body: JSON.stringify({
                        race_id: this.raceId,
                        horse_id: this.selectedHorse,
                        amount: this.betAmount,
                    }),
                });
                const data = await response.json();

                if (data.ok) {
                    this.myBet = true;
                    this.myBetHorseId = data.horse_id;
                    this.selectedHorse = data.horse_id;
                    this.myBetAmount = data.amount;
                    this.setMyBetHorseName(data.horse_id);
                    await this.loadCurrentRace();
                    return;
                }

                window.chatDialog?.alert(data.message || "下注失败", "提示", "#ef4444");
            } catch (error) {
                window.chatDialog?.alert("网络异常，请稍后重试。", "错误", "#ef4444");
            } finally {
                this.submitting = false;
            }
        },

        /**
         * 接收跑马进度更新。
         *
         * @param {Record<string, any>} data 进度广播数据
         * @returns {void}
         */
        updateProgress(data) {
            this.phase = "running";
            this.positions = {
                ...this.positions,
                ...(data.positions || {}),
            };
            this.leaderId = data.leader_id;
        },

        /**
         * 显示结算结果。
         *
         * @param {Record<string, any>} data 结算广播数据
         * @returns {void}
         */
        showResult(data) {
            clearInterval(this.countdownTimer);
            clearInterval(this.settledTimer);
            this.countdownTimer = null;
            this.settledTimer = null;
            this.phase = "settled";
            this.show = true;
            this.totalPool = data.total_pool || this.totalPool;

            const winner = this.horses.find((horse) => horse.id === data.winner_horse_id);
            this.winnerName = winner ? `${winner.emoji}${winner.name}` : data.winner_name || "未知";
            this.winnerEmoji = winner ? winner.emoji : "🐎";

            if (this.myBet && this.myBetHorseId === data.winner_horse_id) {
                this.myWon = true;
                this.myPayout = this.calculatePayout(data);
            } else {
                this.myWon = false;
                this.myPayout = 0;
            }

            this.updateFab(false);
            this.loadHistory();
            this.startSettledCountdown();
        },

        /**
         * 加载历史记录。
         *
         * @returns {Promise<void>}
         */
        async loadHistory() {
            try {
                const data = await this.requestJson(horseRaceUrls().history);
                this.history = (data.history || []).reverse();
            } catch (error) {
                // 历史趋势失败不影响下注主流程。
            }
        },

        /**
         * 更新赛马悬浮按钮显示状态。
         *
         * @param {boolean} visible 是否显示
         * @returns {void}
         */
        updateFab(visible) {
            const fab = document.getElementById("horse-race-fab");

            if (fab && typeof window.Alpine?.$data === "function") {
                window.Alpine.$data(fab).visible = visible;
            }
        },

        /**
         * 关闭面板；下注中保留悬浮按钮方便再次打开。
         *
         * @returns {void}
         */
        close() {
            this.show = false;
            clearInterval(this.settledTimer);
            this.settledTimer = null;

            if (this.phase === "betting") {
                this.updateFab(true);
            }
        },

        /**
         * 从游戏大厅入口打开面板，先同步当前场次最新状态。
         *
         * @returns {Promise<void>}
         */
        async openFromHall() {
            try {
                const data = await this.requestJson(horseRaceUrls().current);
                this.syncUserGold(data.jjb);

                if (data.race) {
                    this.applyRaceState(data.race);
                    this.syncPhaseFromRace(data.race);
                } else {
                    this.resetToIdleState();
                }
            } catch (error) {
                console.warn("[赛马] openFromHall 失败", error);
            }

            this.show = true;
        },

        /**
         * 套用接口返回的场次基础状态。
         *
         * @param {Record<string, any>} race 当前场次
         * @returns {void}
         */
        applyRaceState(race) {
            this.raceId = race.id;
            this.horses = race.horses || this.horses;
            this.totalPool = race.total_pool || 0;
            this.minBet = race.min_bet || DEFAULT_HORSE_RACE_MIN_BET;
            this.maxBet = race.max_bet || DEFAULT_HORSE_RACE_MAX_BET;

            if (race.my_bet) {
                this.myBet = true;
                this.myBetHorseId = race.my_bet.horse_id;
                this.myBetAmount = race.my_bet.amount;
                this.selectedHorse = race.my_bet.horse_id;
                this.setMyBetHorseName(race.my_bet.horse_id);
                return;
            }

            this.myBet = false;
            this.myBetHorseId = null;
            this.myBetHorseName = "";
            this.myBetAmount = 0;
        },

        /**
         * 根据接口状态同步面板阶段和倒计时。
         *
         * @param {Record<string, any>} race 当前场次
         * @returns {void}
         */
        syncPhaseFromRace(race) {
            if (race.status === "betting" && (race.seconds_left ?? 0) > 0) {
                this.phase = "betting";
                this.countdown = race.seconds_left;
                this.totalSeconds = race.seconds_left;
                this.startCountdown();
                return;
            }

            if (race.status === "running") {
                this.phase = "running";
                return;
            }

            this.phase = "settled";
        },

        /**
         * 重置为没有进行中场次的空状态。
         *
         * @returns {void}
         */
        resetToIdleState() {
            clearInterval(this.countdownTimer);
            this.countdownTimer = null;
            this.raceId = null;
            this.horses = [];
            this.totalPool = 0;
            this.myBet = false;
            this.myBetHorseId = null;
            this.myBetHorseName = "";
            this.myBetAmount = 0;
            this.selectedHorse = null;
            this.phase = "idle";
            this.countdown = 0;
        },

        /**
         * 根据马匹 ID 回填本人下注马匹名称。
         *
         * @param {number|string} horseId 马匹 ID
         * @returns {void}
         */
        setMyBetHorseName(horseId) {
            const horse = this.horses.find((item) => item.id === horseId);
            this.myBetHorseName = horse ? `${horse.emoji}${horse.name}` : "";
        },

        /**
         * 按后端同公式还原个人赔付展示值。
         *
         * @param {Record<string, any>} data 结算广播数据
         * @returns {number}
         */
        calculatePayout(data) {
            const winnerPool = Number(data.winner_pool || 0);
            const distributablePool = Number(data.distributable_pool || 0);

            return winnerPool > 0
                ? Math.round(distributablePool * (Number(this.myBetAmount || 0) / winnerPool))
                : 0;
        },

        /**
         * 启动结算弹窗自动关闭倒计时。
         *
         * @returns {void}
         */
        startSettledCountdown() {
            this.settledCountdown = SETTLED_AUTO_CLOSE_SECONDS;
            clearInterval(this.settledTimer);
            this.settledTimer = setInterval(() => {
                this.settledCountdown -= 1;
                if (this.settledCountdown <= 0) {
                    clearInterval(this.settledTimer);
                    this.settledTimer = null;
                    this.close();
                }
            }, 1000);
        },
    };
}

/**
 * 挂载赛马主面板全局组件名，兼容 Blade 的 x-data。
 *
 * @returns {void}
 */
export function bindHorseRacePanelControls() {
    if (typeof window === "undefined") {
        return;
    }

    window.horseRacePanel = horseRacePanel;
}
