const API_URL = "/api/queue/status";
    const STATS_API_URL = "/api/queue/platformStats";
    const THIRD_STATS_API_URL = "/api/queue/thirdPartyStats";
    const platforms = [
        "BDAI", "DB", "DOUBA", "DP", "DPA", "DYAI",
        "KIMI", "TXYB", "TXYBA", "TYQW", "TYQWA", "WXYY", "XHSA"
    ];
    const PLATFORM_NAME_MAP = {
        DOUBA: "豆包·手机版",
        DB: "豆包·网页版",
        DPA: "DeepSeek·手机版",
        DP: "DeepSeek·网页版",
        TYQWA: "千问·手机版",
        TYQW: "千问·网页版",
        TXYBA: "腾讯元宝·手机版",
        TXYB: "腾讯元宝·网页版",
        KIMI: "KIMI·网页版",
        WXYY: "文心·网页版",
        DYAI: "AI抖音·网页版",
        BDAI: "百度AI·网页版",
        XHSA: "红书问一问"
    };
    const PLATFORM_DISPLAY_ORDER = [
        "豆包·手机版",
        "豆包·网页版",
        "千问·手机版",
        "千问·网页版",
        "DeepSeek·手机版",
        "DeepSeek·网页版",
        "腾讯元宝·手机版",
        "腾讯元宝·网页版",
        "KIMI·网页版",
        "文心·网页版",
        "百度AI·网页版",
        "红书问一问",
        "AI抖音·网页版"
    ];
    let currentPanel = "queue";
    let loadedPanels = {queue: false, trend: false, third: false};
    let trendChartMode = "platform";
    let dailySourceMode = "all";
    let lastTrendData = null;
    let thirdTrendMode = "channel";
    let lastThirdData = null;

    function showPanel(panel) {
        currentPanel = panel;
        document.getElementById("queuePanel").classList.toggle("active", panel === "queue");
        document.getElementById("trendPanel").classList.toggle("active", panel === "trend");
        document.getElementById("thirdPanel").classList.toggle("active", panel === "third");
        document.getElementById("queueNavBtn").classList.toggle("active", panel === "queue");
        document.getElementById("trendNavBtn").classList.toggle("active", panel === "trend");
        document.getElementById("thirdNavBtn").classList.toggle("active", panel === "third");
        const pageMeta = {
            queue: {
                title: "队列积压监控",
                desc: "查看各平台 stream_batch / batch 队列积压情况"
            },
            trend: {
                title: "GEO历史任务数量趋势",
                desc: "按时间范围查看各平台历史任务趋势"
            },
            third: {
                title: "三方用量详细分析",
                desc: "查看当前启用渠道的任务量、平台分布与每日趋势"
            }
        };
        document.getElementById("pageTitle").innerText = pageMeta[panel].title;
        document.getElementById("pageDesc").innerText = pageMeta[panel].desc;
        hideError();

        if (!loadedPanels[panel]) {
            refreshCurrentPanel();
        }
    }

    function refreshCurrentPanel() {
        if (currentPanel === "queue") {
            loadQueueStatus();
        } else if (currentPanel === "trend") {
            loadPlatformStats();
        } else {
            loadThirdPartyStats();
        }
    }

    function hideError() {
        const errorBox = document.getElementById("errorBox");
        errorBox.style.display = "none";
        errorBox.innerText = "";
    }

    function showError(message) {
        const errorBox = document.getElementById("errorBox");
        errorBox.style.display = "block";
        errorBox.innerText = message;
    }

    function setTrendLoading(isLoading) {
        document.querySelector(".trend-panel").classList.toggle("loading", isLoading);
    }

    function setThirdLoading(isLoading) {
        document.querySelector(".third-panel").classList.toggle("loading", isLoading);
    }

    function getNumClass(num) {
        if (num === 0) {
            return "num-ok";
        }
        if (num < 500) {
            return "num-warn";
        }
        return "num-danger";
    }

    function getStatus(total) {
        if (total === 0) {
            return {text: "正常", className: "status status-ok"};
        }
        if (total < 500) {
            return {text: "轻微积压", className: "status status-warn"};
        }
        return {text: "严重积压", className: "status status-danger"};
    }

    function renderData(data) {
        const tbody = document.getElementById("queueTableBody");
        let totalCount = 0;
        let streamBatchCount = 0;
        let batchCount = 0;

        tbody.innerHTML = "";

        platforms.forEach(platform => {
            const streamKey = `${platform}:geo:stream_batch:list`;
            const batchKey = `${platform}:geo:batch:list`;
            const streamValue = Number(data[streamKey] || 0);
            const batchValue = Number(data[batchKey] || 0);
            const platformTotal = streamValue + batchValue;
            const status = getStatus(platformTotal);
            const tr = document.createElement("tr");

            streamBatchCount += streamValue;
            batchCount += batchValue;
            totalCount += platformTotal;
            tr.innerHTML = `
                <td class="platform">${platform}</td>
                <td class="num ${getNumClass(streamValue)}">${streamValue}</td>
                <td class="num ${getNumClass(batchValue)}">${batchValue}</td>
                <td class="num ${getNumClass(platformTotal)}">${platformTotal}</td>
                <td><span class="${status.className}">${status.text}</span></td>
            `;
            tbody.appendChild(tr);
        });

        document.getElementById("totalCount").innerText = totalCount;
        document.getElementById("streamBatchCount").innerText = streamBatchCount;
        document.getElementById("batchCount").innerText = batchCount;
        document.getElementById("commitCount").innerText = Number(data["geo:task_commit:list"] || 0);
        document.getElementById("lastTime").innerText = "最后刷新：" + new Date().toLocaleString();
    }

    function getStatsItems(responseData) {
        if (Array.isArray(responseData)) {
            return responseData;
        }
        if (responseData && Array.isArray(responseData.data)) {
            return responseData.data;
        }
        return [];
    }

    function normalizeStats(responseData) {
        return getStatsItems(responseData)
            .map(item => ({
                time: normalizeStatDate(item["时间"] || item.time || item.date || item.begin || ""),
                platform: getPlatformDisplayName(item["平台"] || item.platform || item.name || "未知平台"),
                count: Number(item["数量"] || item.count || item.value || 0),
                systemCount: Number(item.system_count || 0),
                thirdPartyCount: Number(item.third_party_count || 0)
            }))
            .filter(item => (
                item.time
                && Number.isFinite(item.count)
                && Number.isFinite(item.systemCount)
                && Number.isFinite(item.thirdPartyCount)
            ));
    }

    function getPlatformDisplayName(platform) {
        return PLATFORM_NAME_MAP[String(platform || "").trim()] || platform;
    }

    function normalizeStatDate(value) {
        return String(value || "").slice(0, 10);
    }

    function createSvgEl(tag, attrs = {}) {
        const el = document.createElementNS("http://www.w3.org/2000/svg", tag);
        Object.keys(attrs).forEach(key => el.setAttribute(key, attrs[key]));
        return el;
    }

    function renderStackedPlatformChart(chart, labels, platformList, sourcePointMap) {
        const systemColor = "#7138f4";
        const thirdPartyColor = "#b4db2e";
        const getDisplayValue = source => {
            const systemCount = Number(source.systemCount || 0);
            const thirdPartyCount = Number(source.thirdPartyCount || 0);

            if (dailySourceMode === "system") {
                return systemCount;
            }
            if (dailySourceMode === "thirdParty") {
                return thirdPartyCount;
            }
            return systemCount + thirdPartyCount;
        };
        const maxValue = Math.max(
            ...platformList.flatMap(platform => labels.map(label => {
                const source = sourcePointMap.get(`${platform}__${label}`) || {};
                return getDisplayValue(source);
            })),
            1
        );
        const grid = document.createElement("div");
        const legend = document.createElement("div");
        const systemButton = document.createElement("button");
        const thirdPartyButton = document.createElement("button");

        grid.className = "daily-stacked-grid";
        legend.className = "daily-stacked-legend";
        systemButton.className = (
            "daily-source-filter "
            + (dailySourceMode !== "thirdParty" ? "active" : "")
        );
        thirdPartyButton.className = (
            "daily-source-filter "
            + (dailySourceMode !== "system" ? "active" : "")
        );
        systemButton.innerHTML = (
            `<i style="background:${systemColor}"></i>系统用户`
        );
        thirdPartyButton.innerHTML = (
            `<i style="background:${thirdPartyColor}"></i>三方用户`
        );
        systemButton.onclick = () => setDailySourceMode("system");
        thirdPartyButton.onclick = () => setDailySourceMode("thirdParty");
        legend.appendChild(systemButton);
        legend.appendChild(thirdPartyButton);
        chart.appendChild(legend);

        [...labels].reverse().forEach(label => {
            const card = document.createElement("section");
            const head = document.createElement("div");
            const date = document.createElement("strong");
            const total = document.createElement("span");
            const list = document.createElement("div");
            const dayTotal = platformList.reduce((sum, platform) => {
                const source = sourcePointMap.get(`${platform}__${label}`) || {};
                return sum + getDisplayValue(source);
            }, 0);

            card.className = "daily-stacked-card";
            head.className = "daily-stacked-head";
            date.textContent = label;
            total.textContent = `总量 ${dayTotal}`;
            list.className = "daily-stacked-list";
            head.appendChild(date);
            head.appendChild(total);
            card.appendChild(head);

            platformList.forEach(platform => {
                const source = sourcePointMap.get(`${platform}__${label}`) || {};
                const systemCount = Number(source.systemCount || 0);
                const thirdPartyCount = Number(source.thirdPartyCount || 0);
                const rowTotal = getDisplayValue(source);
                const row = document.createElement("div");
                const nameWrap = document.createElement("div");
                const name = document.createElement("div");
                const sourceNumbers = document.createElement("div");
                const track = document.createElement("div");
                const stack = document.createElement("div");
                const systemBar = document.createElement("span");
                const thirdPartyBar = document.createElement("span");
                const value = document.createElement("strong");
                const totalWidth = (rowTotal / maxValue) * 100;
                const systemWidth = dailySourceMode === "thirdParty"
                    ? 0
                    : (
                        dailySourceMode === "system"
                            ? 100
                            : (rowTotal ? (systemCount / rowTotal) * 100 : 0)
                    );
                const thirdPartyWidth = dailySourceMode === "system"
                    ? 0
                    : (
                        dailySourceMode === "thirdParty"
                            ? 100
                            : (rowTotal ? (thirdPartyCount / rowTotal) * 100 : 0)
                    );

                row.className = "daily-stacked-row";
                nameWrap.className = "daily-stacked-name-wrap";
                name.className = "daily-stacked-name";
                sourceNumbers.className = "daily-stacked-source-numbers";
                track.className = "daily-stacked-track";
                stack.className = "daily-stacked-bar";
                systemBar.className = "daily-stacked-system";
                thirdPartyBar.className = "daily-stacked-third-party";
                value.className = "daily-stacked-value";
                name.textContent = platform;
                if (dailySourceMode === "system") {
                    sourceNumbers.innerHTML = (
                        `<span>系统 ${systemCount}</span>`
                    );
                } else if (dailySourceMode === "thirdParty") {
                    sourceNumbers.innerHTML = (
                        `<span>三方 ${thirdPartyCount}</span>`
                    );
                } else {
                    sourceNumbers.innerHTML = `
                        <span>系统 ${systemCount}</span>
                        <span>三方 ${thirdPartyCount}</span>
                    `;
                }
                stack.style.width = `${totalWidth}%`;
                systemBar.style.width = `${systemWidth}%`;
                thirdPartyBar.style.width = `${thirdPartyWidth}%`;
                stack.title = (
                    `${platform} ${label}：`
                    + `系统用户 ${systemCount}，`
                    + `三方用户 ${thirdPartyCount}，`
                    + `合计 ${rowTotal}`
                );
                value.textContent = rowTotal;

                nameWrap.appendChild(name);
                nameWrap.appendChild(sourceNumbers);
                stack.appendChild(systemBar);
                stack.appendChild(thirdPartyBar);
                track.appendChild(stack);
                row.appendChild(nameWrap);
                row.appendChild(track);
                row.appendChild(value);
                list.appendChild(row);
            });
            card.appendChild(list);
            grid.appendChild(card);
        });

        chart.appendChild(grid);
    }

    function setDailySourceMode(mode) {
        dailySourceMode = dailySourceMode === mode ? "all" : mode;
        if (!lastTrendData) {
            return;
        }

        const chart = document.getElementById("platformTrendChart");
        chart.innerHTML = "";
        renderStackedPlatformChart(
            chart,
            lastTrendData.labels,
            lastTrendData.platformList,
            lastTrendData.sourcePointMap
        );
    }

    function renderPlatformTrend(responseData) {
        const chart = document.getElementById("platformTrendChart");
        const summary = document.getElementById("trendSummary");
        const statsNote = document.getElementById("statsNote");
        const colors = ["#7138f4", "#16a34a", "#f59e0b", "#dc2626", "#9b5cff", "#0891b2", "#db2777", "#475569"];
        const items = normalizeStats(responseData);

        chart.innerHTML = "";
        summary.innerHTML = "";

        if (!items.length) {
            statsNote.innerText = "暂无趋势数据";
            chart.innerHTML = '<div class="chart-empty">当前时间范围暂无历史任务趋势数据</div>';
            return;
        }

        const chartLabels = [...new Set(items.map(item => item.time))].sort();
        const oldestDate = chartLabels[0];
        const newestDate = chartLabels[chartLabels.length - 1];
        const platformTotals = new Map();
        const pointMap = new Map();
        const sourcePointMap = new Map();

        items.forEach(item => {
            platformTotals.set(item.platform, (platformTotals.get(item.platform) || 0) + item.count);
            const pointKey = `${item.platform}__${item.time}`;
            pointMap.set(pointKey, (pointMap.get(pointKey) || 0) + item.count);
            const sourcePoint = sourcePointMap.get(pointKey) || {
                systemCount: 0,
                thirdPartyCount: 0
            };
            sourcePoint.systemCount += item.systemCount;
            sourcePoint.thirdPartyCount += item.thirdPartyCount;
            sourcePointMap.set(pointKey, sourcePoint);
        });

        const platformList = [...platformTotals.entries()]
            .sort((a, b) => {
                const aIndex = PLATFORM_DISPLAY_ORDER.indexOf(a[0]);
                const bIndex = PLATFORM_DISPLAY_ORDER.indexOf(b[0]);
                const normalizedAIndex = aIndex === -1
                    ? Number.MAX_SAFE_INTEGER
                    : aIndex;
                const normalizedBIndex = bIndex === -1
                    ? Number.MAX_SAFE_INTEGER
                    : bIndex;

                if (normalizedAIndex !== normalizedBIndex) {
                    return normalizedAIndex - normalizedBIndex;
                }
                return b[1] - a[1];
            })
            .map(([platform]) => platform);
        const platformColorMap = new Map(platformList.map((platform, index) => [platform, colors[index % colors.length]]));
        const dayTotals = chartLabels.map(label => ({
            date: label,
            total: platformList.reduce((sum, platform) => sum + (pointMap.get(`${platform}__${label}`) || 0), 0)
        }));

        lastTrendData = {
            labels: chartLabels,
            platformList,
            pointMap,
            sourcePointMap,
            platformColorMap,
            dayTotals
        };

        renderStackedPlatformChart(
            chart,
            chartLabels,
            platformList,
            sourcePointMap
        );
        renderTrendSummary();
        statsNote.innerText = `共 ${platformList.length} 个平台，${oldestDate} 至 ${newestDate}`;
        document.getElementById("lastTime").innerText = "最后刷新：" + new Date().toLocaleString();
    }

    function renderTrendSummary() {
        if (!lastTrendData) {
            return;
        }

        const summary = document.getElementById("trendSummary");
        const titleText = trendChartMode === "total" ? "每日总量趋势" : "各平台每日趋势";
        const series = trendChartMode === "total"
            ? [{
                name: "总量",
                color: "#7138f4",
                values: lastTrendData.dayTotals.map(item => item.total)
            }]
            : lastTrendData.platformList.map(platform => ({
                name: platform,
                color: lastTrendData.platformColorMap.get(platform),
                values: lastTrendData.labels.map(label => lastTrendData.pointMap.get(`${platform}__${label}`) || 0)
            }));
        const maxValue = Math.max(...series.flatMap(item => item.values), 1);
        const width = Math.max(summary.clientWidth - 32, 720);
        const height = 220;
        const padding = {top: 26, right: 18, bottom: 40, left: 52};
        const plotWidth = width - padding.left - padding.right;
        const plotHeight = height - padding.top - padding.bottom;
        const xScale = index => lastTrendData.labels.length > 1
            ? padding.left + (plotWidth / (lastTrendData.labels.length - 1)) * index
            : padding.left + plotWidth / 2;
        const yScale = value => padding.top + plotHeight - (value / maxValue) * plotHeight;
        const head = document.createElement("div");
        const title = document.createElement("span");
        const actions = document.createElement("div");
        const range = document.createElement("span");
        const switchWrap = document.createElement("div");
        const platformBtn = document.createElement("button");
        const totalBtn = document.createElement("button");
        const svg = createSvgEl("svg", {viewBox: `0 0 ${width} ${height}`, role: "img"});
        const tooltip = document.createElement("div");

        summary.innerHTML = "";
        head.className = "trend-summary-title";
        title.className = "trend-summary-title-main";
        actions.className = "trend-summary-actions";
        range.className = "trend-summary-range";
        switchWrap.className = "trend-switch";
        platformBtn.className = `trend-switch-btn ${trendChartMode === "platform" ? "active" : ""}`;
        totalBtn.className = `trend-switch-btn ${trendChartMode === "total" ? "active" : ""}`;
        title.innerText = titleText;
        range.innerText = `${lastTrendData.labels[0]} 至 ${lastTrendData.labels[lastTrendData.labels.length - 1]}`;
        platformBtn.innerText = "平台";
        totalBtn.innerText = "总量";
        platformBtn.onclick = () => setTrendChartMode("platform");
        totalBtn.onclick = () => setTrendChartMode("total");
        switchWrap.appendChild(platformBtn);
        switchWrap.appendChild(totalBtn);
        head.appendChild(title);
        actions.appendChild(range);
        actions.appendChild(switchWrap);
        head.appendChild(actions);
        tooltip.className = "trend-tooltip";

        for (let i = 0; i <= 3; i++) {
            const value = Math.round((maxValue / 3) * i);
            const y = yScale(value);
            svg.appendChild(createSvgEl("line", {
                x1: padding.left,
                y1: y,
                x2: width - padding.right,
                y2: y,
                stroke: i === 0 ? "#cbd5e1" : "#e5e7eb",
                "stroke-width": "1"
            }));
            const axisText = createSvgEl("text", {
                x: padding.left - 10,
                y: y + 4,
                "text-anchor": "end",
                class: "trend-label"
            });
            axisText.textContent = value;
            svg.appendChild(axisText);
        }

        series.forEach(line => {
            const points = line.values.map((value, index) => ({
                date: lastTrendData.labels[index],
                value,
                x: xScale(index),
                y: yScale(value)
            }));

            svg.appendChild(createSvgEl("polyline", {
                points: points.map(point => `${point.x},${point.y}`).join(" "),
                fill: "none",
                stroke: line.color,
                "stroke-width": trendChartMode === "total" ? "3" : "2",
                "stroke-opacity": trendChartMode === "total" ? "1" : "0.78",
                "stroke-linecap": "round",
                "stroke-linejoin": "round"
            }));

            points.forEach(point => {
                svg.appendChild(createSvgEl("circle", {
                    cx: point.x,
                    cy: point.y,
                    r: trendChartMode === "total" ? "5" : "3",
                    fill: line.color,
                    stroke: "#fff",
                    "stroke-width": "2"
                }));

                if (trendChartMode === "total") {
                    const totalText = createSvgEl("text", {
                        x: point.x,
                        y: Math.max(14, point.y - 10),
                        "text-anchor": "middle",
                        class: "trend-total-label"
                    });
                    totalText.textContent = point.value;
                    svg.appendChild(totalText);
                }
            });
        });

        lastTrendData.labels.forEach((label, index) => {
            const dateText = createSvgEl("text", {
                x: xScale(index),
                y: height - 12,
                "text-anchor": "middle",
                class: "trend-label"
            });
            dateText.textContent = label.slice(5);
            svg.appendChild(dateText);
        });

        lastTrendData.labels.forEach((label, index) => {
            const left = index === 0 ? padding.left : (xScale(index - 1) + xScale(index)) / 2;
            const right = index === lastTrendData.labels.length - 1
                ? width - padding.right
                : (xScale(index) + xScale(index + 1)) / 2;
            const hit = createSvgEl("rect", {
                x: left,
                y: padding.top,
                width: Math.max(12, right - left),
                height: plotHeight,
                fill: "transparent",
                "pointer-events": "all",
                class: "trend-hover-hit"
            });

            hit.addEventListener("mouseenter", event => showTrendDayTooltip(event, label));
            hit.addEventListener("mousemove", moveTrendDayTooltip);
            hit.addEventListener("mouseleave", hideTrendDayTooltip);
            svg.appendChild(hit);
        });

        summary.appendChild(head);
        summary.appendChild(svg);
        summary.appendChild(tooltip);
    }

    function setTrendChartMode(mode) {
        trendChartMode = mode;
        renderTrendSummary();
    }

    function moveTrendDayTooltip(event) {
        const tooltip = document.querySelector(".trend-tooltip");

        if (!tooltip) {
            return;
        }

        const offset = 14;
        const tooltipWidth = tooltip.offsetWidth || 280;
        const tooltipHeight = tooltip.offsetHeight || 120;
        let left = event.clientX + offset;
        let top = event.clientY + offset;

        if (left + tooltipWidth > window.innerWidth - 12) {
            left = event.clientX - tooltipWidth - offset;
        }
        if (top + tooltipHeight > window.innerHeight - 12) {
            top = event.clientY - tooltipHeight - offset;
        }

        tooltip.style.left = `${Math.max(12, left)}px`;
        tooltip.style.top = `${Math.max(12, top)}px`;
    }

    function showTrendDayTooltip(event, date) {
        const tooltip = document.querySelector(".trend-tooltip");

        if (!tooltip || !lastTrendData) {
            return;
        }

        const dayItems = lastTrendData.platformList.map(platform => ({
            platform,
            value: lastTrendData.pointMap.get(`${platform}__${date}`) || 0,
            color: lastTrendData.platformColorMap.get(platform)
        })).sort((a, b) => b.value - a.value);
        const dayTotal = dayItems.reduce((sum, item) => sum + item.value, 0);
        tooltip.innerHTML = "";

        const title = document.createElement("div");
        const total = document.createElement("div");
        const totalValue = document.createElement("strong");
        const list = document.createElement("div");

        title.className = "trend-tooltip-title";
        title.innerText = date;
        total.className = "trend-tooltip-total";
        total.innerHTML = "<span>当天总量</span>";
        totalValue.innerText = dayTotal;
        total.appendChild(totalValue);
        list.className = "trend-tooltip-list";

        dayItems.forEach(item => {
            const row = document.createElement("div");
            const dot = document.createElement("span");
            const name = document.createElement("span");
            const count = document.createElement("span");

            row.className = "trend-tooltip-row";
            dot.className = "trend-tooltip-dot";
            dot.style.background = item.color;
            name.className = "trend-tooltip-name";
            name.innerText = item.platform;
            count.className = "trend-tooltip-count";
            count.innerText = item.value;
            row.appendChild(dot);
            row.appendChild(name);
            row.appendChild(count);
            list.appendChild(row);
        });

        tooltip.appendChild(title);
        tooltip.appendChild(total);
        tooltip.appendChild(list);
        tooltip.style.display = "block";
        moveTrendDayTooltip(event);
    }

    function hideTrendDayTooltip() {
        const tooltip = document.querySelector(".trend-tooltip");

        if (tooltip) {
            tooltip.style.display = "none";
        }
    }

    function toDateInputValue(date) {
        const offsetDate = new Date(date.getTime() - date.getTimezoneOffset() * 60000);
        return offsetDate.toISOString().slice(0, 10);
    }

    function setQuickRange(days, shouldLoad = true) {
        const beginInput = document.getElementById("beginTime");
        const endInput = document.getElementById("endTime");
        const now = new Date();
        const start = new Date(now);

        start.setDate(start.getDate() - days + 1);
        start.setHours(0, 0, 0, 0);
        beginInput.value = toDateInputValue(start);
        endInput.value = toDateInputValue(now);
        document.getElementById("range3Btn").classList.toggle("active", days === 3);
        document.getElementById("range7Btn").classList.toggle("active", days === 7);
        document.getElementById("range30Btn").classList.toggle("active", days === 30);

        if (shouldLoad && currentPanel === "trend") {
            loadPlatformStats();
        } else if (shouldLoad) {
            loadedPanels.trend = false;
        }
    }

    function clearQuickRangeActive() {
        document.getElementById("range3Btn").classList.remove("active");
        document.getElementById("range7Btn").classList.remove("active");
        document.getElementById("range30Btn").classList.remove("active");
    }

    function handleDateRangeChange() {
        clearQuickRangeActive();
        loadedPanels.trend = false;

        if (currentPanel === "trend") {
            loadPlatformStats();
        }
    }

    function buildStatsUrl() {
        const begin = document.getElementById("beginTime").value;
        const end = document.getElementById("endTime").value;

        if (!begin || !end) {
            throw new Error("请选择开始时间和结束时间");
        }
        if (begin > end) {
            throw new Error("开始时间不能晚于结束时间");
        }

        return `${STATS_API_URL}?${new URLSearchParams({begin, end}).toString()}`;
    }

    async function fetchJson(url) {
        const res = await fetch(url, {method: "GET", cache: "no-store"});

        if (!res.ok) {
            throw new Error("接口请求失败，状态码：" + res.status);
        }

        return res.json();
    }

    async function loadQueueStatus() {
        hideError();

        try {
            renderData(await fetchJson(API_URL));
            loadedPanels.queue = true;
        } catch (e) {
            showError("队列数据加载失败：" + e.message);
        }
    }

    async function loadPlatformStats() {
        const statsNote = document.getElementById("statsNote");
        hideError();
        statsNote.innerText = "加载中";
        trendChartMode = "platform";
        dailySourceMode = "all";
        setTrendLoading(true);

        try {
            renderPlatformTrend(await fetchJson(buildStatsUrl()));
            loadedPanels.trend = true;
        } catch (e) {
            statsNote.innerText = "加载失败";
            showError("历史任务趋势加载失败：" + e.message);
        } finally {
            setTrendLoading(false);
        }
    }

    function formatNumber(value) {
        return Number(value || 0).toLocaleString("zh-CN");
    }

    function setThirdQuickRange(days, shouldLoad = true) {
        const beginInput = document.getElementById("thirdBeginTime");
        const endInput = document.getElementById("thirdEndTime");
        const now = new Date();
        const start = new Date(now);

        start.setDate(start.getDate() - days + 1);
        start.setHours(0, 0, 0, 0);
        beginInput.value = toDateInputValue(start);
        endInput.value = toDateInputValue(now);
        [3, 7, 30].forEach(rangeDays => {
            document.getElementById(`thirdRange${rangeDays}Btn`).classList.toggle(
                "active",
                days === rangeDays
            );
        });

        if (shouldLoad && currentPanel === "third") {
            loadThirdPartyStats();
        } else if (shouldLoad) {
            loadedPanels.third = false;
        }
    }

    function clearThirdQuickRangeActive() {
        [3, 7, 30].forEach(days => {
            document.getElementById(`thirdRange${days}Btn`).classList.remove("active");
        });
    }

    function buildThirdStatsUrl() {
        const begin = document.getElementById("thirdBeginTime").value;
        const end = document.getElementById("thirdEndTime").value;
        const channel = document.getElementById("thirdChannelFilter").value;
        const platform = document.getElementById("thirdPlatformFilter").value;

        if (!begin || !end) {
            throw new Error("请选择开始时间和结束时间");
        }
        if (begin > end) {
            throw new Error("开始时间不能晚于结束时间");
        }

        return `${THIRD_STATS_API_URL}?${new URLSearchParams({
            begin,
            end,
            channel,
            platform
        }).toString()}`;
    }

    function refreshCustomSelect(select) {
        const custom = select._customSelect;
        if (!custom) {
            return;
        }

        custom.menu.innerHTML = "";
        Array.from(select.options).forEach(option => {
            const item = document.createElement("button");
            item.type = "button";
            item.className = "custom-select-option";
            item.textContent = option.textContent;
            item.dataset.value = option.value;
            item.classList.toggle("selected", option.value === select.value);
            item.setAttribute(
                "aria-selected",
                option.value === select.value ? "true" : "false"
            );
            item.onclick = () => {
                if (select.value !== option.value) {
                    select.value = option.value;
                    select.dispatchEvent(new Event("change", {bubbles: true}));
                }
                refreshCustomSelect(select);
                custom.wrapper.classList.remove("open");
                custom.trigger.setAttribute("aria-expanded", "false");
                custom.trigger.focus();
            };
            custom.menu.appendChild(item);
        });

        const selectedOption = select.options[select.selectedIndex];
        custom.value.textContent = selectedOption
            ? selectedOption.textContent
            : "请选择";
    }

    function initCustomSelect(select) {
        if (select._customSelect) {
            refreshCustomSelect(select);
            return;
        }

        const wrapper = document.createElement("div");
        const trigger = document.createElement("button");
        const value = document.createElement("span");
        const arrow = document.createElement("span");
        const menu = document.createElement("div");

        wrapper.className = "custom-select";
        trigger.type = "button";
        trigger.className = "custom-select-trigger";
        trigger.setAttribute("aria-haspopup", "listbox");
        trigger.setAttribute("aria-expanded", "false");
        value.className = "custom-select-value";
        arrow.className = "custom-select-arrow";
        menu.className = "custom-select-menu";
        menu.setAttribute("role", "listbox");

        trigger.appendChild(value);
        trigger.appendChild(arrow);
        wrapper.appendChild(trigger);
        wrapper.appendChild(menu);
        select.insertAdjacentElement("afterend", wrapper);
        select.classList.add("native-select-hidden");
        select._customSelect = {wrapper, trigger, value, menu};

        trigger.onclick = event => {
            event.stopPropagation();
            document.querySelectorAll(".custom-select.open").forEach(item => {
                if (item !== wrapper) {
                    item.classList.remove("open");
                    item.querySelector(".custom-select-trigger")
                        ?.setAttribute("aria-expanded", "false");
                }
            });
            const isOpen = wrapper.classList.toggle("open");
            trigger.setAttribute("aria-expanded", isOpen ? "true" : "false");
        };
        trigger.onkeydown = event => {
            if (event.key === "Escape") {
                wrapper.classList.remove("open");
                trigger.setAttribute("aria-expanded", "false");
            }
        };
        refreshCustomSelect(select);
    }

    function updateThirdFilterOptions(data) {
        const channelSelect = document.getElementById("thirdChannelFilter");
        const platformSelect = document.getElementById("thirdPlatformFilter");
        const selectedChannel = channelSelect.value;
        const selectedPlatform = platformSelect.value;

        channelSelect.innerHTML = '<option value="">全部渠道</option>';
        (data.channels || []).forEach(item => {
            const option = document.createElement("option");
            option.value = item.channel;
            option.textContent = item.remark || "-";
            channelSelect.appendChild(option);
        });
        channelSelect.value = selectedChannel;

        platformSelect.innerHTML = '<option value="">全部平台</option>';
        platforms.forEach(platform => {
            const option = document.createElement("option");
            option.value = platform;
            option.textContent = getPlatformDisplayName(platform);
            platformSelect.appendChild(option);
        });
        platformSelect.value = selectedPlatform;
        refreshCustomSelect(channelSelect);
        refreshCustomSelect(platformSelect);
    }

    function renderThirdMetrics(metrics) {
        document.getElementById("thirdTotalMetric").textContent = formatNumber(metrics.third_total);
        document.getElementById("thirdDailyAverageMetric").textContent = formatNumber(metrics.daily_average);
        document.getElementById("thirdRatioMetric").textContent = `${Number(metrics.third_ratio || 0).toFixed(2)}%`;
        document.getElementById("thirdShareMetric").textContent = formatNumber(metrics.share_total);
        document.getElementById("thirdEnabledMetric").textContent = formatNumber(metrics.enabled_channel_count);
    }

    function renderThirdRanking(items) {
        const container = document.getElementById("thirdRanking");
        const maxValue = Math.max(...items.map(item => Number(item.task_count || 0)), 1);
        container.innerHTML = "";

        if (!items.length) {
            container.innerHTML = '<div class="third-empty">暂无渠道用量</div>';
            return;
        }

        const list = document.createElement("div");
        list.className = "third-ranking-list";
        items.forEach((item, index) => {
            const row = document.createElement("button");
            const rank = document.createElement("span");
            const name = document.createElement("span");
            const bar = document.createElement("span");
            const barInner = document.createElement("span");
            const count = document.createElement("strong");

            row.className = "third-ranking-row";
            rank.className = "third-ranking-index";
            name.className = "third-ranking-name";
            bar.className = "third-ranking-bar";
            barInner.className = "third-ranking-bar-inner";
            count.className = "third-ranking-count";
            rank.textContent = index + 1;
            name.textContent = item.remark || "-";
            barInner.style.width = `${(Number(item.task_count || 0) / maxValue) * 100}%`;
            count.textContent = formatNumber(item.task_count);
            bar.appendChild(barInner);
            row.appendChild(rank);
            row.appendChild(name);
            row.appendChild(bar);
            row.appendChild(count);
            row.onclick = () => {
                document.getElementById("thirdChannelFilter").value = item.channel;
                loadThirdPartyStats();
            };
            list.appendChild(row);
        });
        container.appendChild(list);
    }

    function getThirdDateLabels() {
        const begin = document.getElementById("thirdBeginTime").value;
        const end = document.getElementById("thirdEndTime").value;
        const labels = [];
        const current = new Date(`${begin}T00:00:00`);
        const endDate = new Date(`${end}T00:00:00`);

        while (current <= endDate) {
            labels.push(toDateInputValue(current));
            current.setDate(current.getDate() + 1);
        }
        return labels;
    }

    function normalizeThirdPt(value) {
        const text = String(value || "");
        return text.length === 8
            ? `${text.slice(0, 4)}-${text.slice(4, 6)}-${text.slice(6, 8)}`
            : text.slice(0, 10);
    }

    function renderThirdTrend() {
        const chart = document.getElementById("thirdTrendChart");
        chart.innerHTML = "";
        if (!lastThirdData) {
            return;
        }

        const selectedChannel = document.getElementById("thirdChannelFilter").value;
        const channels = selectedChannel
            ? [selectedChannel]
            : (lastThirdData.channels || []).map(item => item.channel);
        const channelRemarkMap = new Map(
            (lastThirdData.channels || []).map(item => [
                item.channel,
                item.remark || "-"
            ])
        );
        const labels = getThirdDateLabels();
        const dailyMap = new Map();
        (lastThirdData.daily || []).forEach(item => {
            dailyMap.set(
                `${item.channel}__${normalizeThirdPt(item.pt)}`,
                Number(item.count || 0)
            );
        });
        const colors = [
            "#7138f4", "#16a34a", "#f59e0b", "#dc2626",
            "#7c3aed", "#0891b2", "#db2777", "#475569",
            "#0f766e", "#9333ea", "#ea580c", "#4f46e5",
            "#65a30d", "#be123c", "#0369a1", "#854d0e"
        ];
        const series = thirdTrendMode === "total"
            ? [{
                name: "每日总量",
                color: "#7138f4",
                values: labels.map(label => channels.reduce(
                    (sum, channel) => (
                        sum + (dailyMap.get(`${channel}__${label}`) || 0)
                    ),
                    0
                ))
            }]
            : channels.map((channel, index) => ({
                name: channelRemarkMap.get(channel) || "-",
                color: colors[index % colors.length],
                values: labels.map(label => dailyMap.get(`${channel}__${label}`) || 0)
            }));

        if (!series.length) {
            chart.innerHTML = '<div class="third-empty">暂无趋势数据</div>';
            return;
        }

        const legend = document.createElement("div");
        const scroll = document.createElement("div");
        const width = Math.max(chart.clientWidth - 28, labels.length * 90 + 90);
        const height = 300;
        const padding = {top: 24, right: 20, bottom: 42, left: 58};
        const plotWidth = width - padding.left - padding.right;
        const plotHeight = height - padding.top - padding.bottom;
        const maxValue = Math.max(...series.flatMap(item => item.values), 1);
        const xScale = index => labels.length > 1
            ? padding.left + plotWidth / (labels.length - 1) * index
            : padding.left + plotWidth / 2;
        const yScale = value => padding.top + plotHeight - value / maxValue * plotHeight;
        const svg = createSvgEl("svg", {
            viewBox: `0 0 ${width} ${height}`,
            width,
            height,
            role: "img"
        });

        legend.className = "third-trend-legend";
        scroll.className = "third-trend-scroll";
        series.forEach(item => {
            const legendItem = document.createElement("span");
            legendItem.innerHTML = `<i style="background:${item.color}"></i>`;
            legendItem.appendChild(document.createTextNode(item.name));
            legend.appendChild(legendItem);
        });

        for (let index = 0; index <= 4; index++) {
            const value = Math.round(maxValue / 4 * index);
            const y = yScale(value);
            svg.appendChild(createSvgEl("line", {
                x1: padding.left,
                y1: y,
                x2: width - padding.right,
                y2: y,
                stroke: index === 0 ? "#cbd5e1" : "#e5e7eb",
                "stroke-width": "1"
            }));
            const text = createSvgEl("text", {
                x: padding.left - 9,
                y: y + 4,
                "text-anchor": "end",
                class: "third-trend-label"
            });
            text.textContent = value;
            svg.appendChild(text);
        }

        series.forEach(item => {
            const points = item.values.map((value, index) => ({
                value,
                x: xScale(index),
                y: yScale(value),
                date: labels[index]
            }));
            svg.appendChild(createSvgEl("polyline", {
                points: points.map(point => `${point.x},${point.y}`).join(" "),
                fill: "none",
                stroke: item.color,
                "stroke-width": thirdTrendMode === "total" ? "3" : "2",
                "stroke-linecap": "round",
                "stroke-linejoin": "round"
            }));
            points.forEach(point => {
                const circle = createSvgEl("circle", {
                    cx: point.x,
                    cy: point.y,
                    r: thirdTrendMode === "total" ? "4" : "3",
                    fill: item.color,
                    stroke: "#fff",
                    "stroke-width": "1.5"
                });
                const title = createSvgEl("title");
                title.textContent = `${item.name} ${point.date}: ${point.value}`;
                circle.appendChild(title);
                svg.appendChild(circle);
            });
        });

        labels.forEach((label, index) => {
            const text = createSvgEl("text", {
                x: xScale(index),
                y: height - 13,
                "text-anchor": "middle",
                class: "third-trend-label"
            });
            text.textContent = label.slice(5);
            svg.appendChild(text);
        });

        scroll.appendChild(svg);
        chart.appendChild(legend);
        chart.appendChild(scroll);
    }

    function setThirdTrendMode(mode) {
        thirdTrendMode = mode;
        document.getElementById("thirdTrendChannelBtn").classList.toggle("active", mode === "channel");
        document.getElementById("thirdTrendTotalBtn").classList.toggle("active", mode === "total");
        renderThirdTrend();
    }

    function renderThirdMatrix(data) {
        const table = document.getElementById("thirdMatrixTable");
        const selectedChannel = document.getElementById("thirdChannelFilter").value;
        const channels = selectedChannel
            ? [selectedChannel]
            : (data.channels || []).map(item => item.channel);
        const platforms = [...(data.platforms || [])].sort((left, right) => {
            const leftOrder = PLATFORM_DISPLAY_ORDER.indexOf(
                getPlatformDisplayName(left)
            );
            const rightOrder = PLATFORM_DISPLAY_ORDER.indexOf(
                getPlatformDisplayName(right)
            );
            return (
                (leftOrder === -1 ? PLATFORM_DISPLAY_ORDER.length : leftOrder)
                - (rightOrder === -1 ? PLATFORM_DISPLAY_ORDER.length : rightOrder)
            );
        });
        const channelRemarkMap = new Map(
            (data.channels || []).map(item => [
                item.channel,
                item.remark || "-"
            ])
        );
        const valueMap = new Map();
        (data.matrix || []).forEach(item => {
            valueMap.set(`${item.channel}__${item.platform}`, Number(item.count || 0));
        });
        const maxValue = Math.max(...valueMap.values(), 1);
        table.innerHTML = "";

        const thead = document.createElement("thead");
        const headRow = document.createElement("tr");
        const channelHead = document.createElement("th");
        channelHead.textContent = "渠道";
        headRow.appendChild(channelHead);
        platforms.forEach(platform => {
            const th = document.createElement("th");
            th.textContent = getPlatformDisplayName(platform);
            headRow.appendChild(th);
        });
        const totalHead = document.createElement("th");
        totalHead.textContent = "合计";
        headRow.appendChild(totalHead);
        thead.appendChild(headRow);
        table.appendChild(thead);

        const tbody = document.createElement("tbody");
        channels.forEach(channel => {
            const row = document.createElement("tr");
            const channelCell = document.createElement("td");
            let rowTotal = 0;
            channelCell.textContent = channelRemarkMap.get(channel) || "-";
            row.appendChild(channelCell);
            platforms.forEach(platform => {
                const count = valueMap.get(`${channel}__${platform}`) || 0;
                const cell = document.createElement("td");
                rowTotal += count;
                cell.textContent = formatNumber(count);
                cell.style.background = `rgba(113, 56, 244, ${0.04 + count / maxValue * 0.52})`;
                cell.style.color = count / maxValue > 0.58 ? "#fff" : "#1e293b";
                row.appendChild(cell);
            });
            const totalCell = document.createElement("td");
            totalCell.textContent = formatNumber(rowTotal);
            totalCell.className = "third-matrix-total";
            row.appendChild(totalCell);
            tbody.appendChild(row);
        });
        table.appendChild(tbody);
    }

    function renderThirdDetails(items) {
        const tbody = document.getElementById("thirdDetailBody");
        tbody.innerHTML = "";
        items.forEach(item => {
            const row = document.createElement("tr");
            [
                item.remark || "-",
                formatNumber(item.task_count),
                `${Number(item.ratio || 0).toFixed(2)}%`,
                formatNumber(item.share_count),
                formatNumber(item.platform_count),
                normalizeThirdPt(item.last_date) || "-",
                formatNumber(item.daily_limit),
                formatNumber(item.total_limit)
            ].forEach(value => {
                const cell = document.createElement("td");
                cell.textContent = value;
                row.appendChild(cell);
            });
            tbody.appendChild(row);
        });
    }

    function renderThirdPartyStats(responseData) {
        const data = responseData && responseData.data
            ? responseData.data
            : {};
        lastThirdData = data;
        updateThirdFilterOptions(data);
        renderThirdMetrics(data.metrics || {});
        renderThirdRanking(data.channel_ranking || []);
        renderThirdTrend();
        renderThirdMatrix(data);
        renderThirdDetails(data.channel_details || []);

        const labels = getThirdDateLabels();
        document.getElementById("thirdStatsNote").textContent = (
            `当前启用 ${Number((data.metrics || {}).enabled_channel_count || 0)} 个渠道，`
            + `${labels[0] || "-"} 至 ${labels[labels.length - 1] || "-"}`
        );
        document.getElementById("lastTime").innerText = "最后刷新：" + new Date().toLocaleString();
    }

    async function loadThirdPartyStats() {
        const note = document.getElementById("thirdStatsNote");
        hideError();
        note.textContent = "加载中";
        setThirdLoading(true);

        try {
            renderThirdPartyStats(await fetchJson(buildThirdStatsUrl()));
            loadedPanels.third = true;
        } catch (error) {
            note.textContent = "加载失败";
            showError("三方用量数据加载失败：" + error.message);
        } finally {
            setThirdLoading(false);
        }
    }

    initCustomSelect(document.getElementById("thirdChannelFilter"));
    initCustomSelect(document.getElementById("thirdPlatformFilter"));
    document.addEventListener("click", event => {
        if (!event.target.closest(".custom-select")) {
            document.querySelectorAll(".custom-select.open").forEach(item => {
                item.classList.remove("open");
                item.querySelector(".custom-select-trigger")
                    ?.setAttribute("aria-expanded", "false");
            });
        }
    });
    document.getElementById("beginTime").addEventListener("change", handleDateRangeChange);
    document.getElementById("endTime").addEventListener("change", handleDateRangeChange);
    document.getElementById("thirdBeginTime").addEventListener("change", () => {
        clearThirdQuickRangeActive();
        loadThirdPartyStats();
    });
    document.getElementById("thirdEndTime").addEventListener("change", () => {
        clearThirdQuickRangeActive();
        loadThirdPartyStats();
    });
    document.getElementById("thirdChannelFilter").addEventListener("change", loadThirdPartyStats);
    document.getElementById("thirdPlatformFilter").addEventListener("change", loadThirdPartyStats);
    setQuickRange(3, false);
    setThirdQuickRange(3, false);
    loadQueueStatus();
