/*
Copyright (C) 2025 QuantumNous

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

For commercial licensing, please contact support@quantumnous.com
*/

import { Toast, Pagination } from '@douyinfe/semi-ui';
import { toastConstants } from '../constants';
import React from 'react';
import { toast } from 'react-toastify';
import {
  THINK_TAG_REGEX,
  MESSAGE_ROLES,
} from '../constants/playground.constants';
import { TABLE_COMPACT_MODES_KEY } from '../constants';
import { USER_ROLES } from '../constants/user.constants';
import { MOBILE_BREAKPOINT } from '../hooks/common/useIsMobile';

const HTMLToastContent = ({ htmlContent }) => {
  return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
};
export default HTMLToastContent;

/** 是否为代理：后端 is_distributor 为 0/1，兼容历史 true 与 role===5 */
export function userIsDistributorUser(userLike) {
  if (!userLike || typeof userLike !== 'object') return false;
  if (userLike.is_distributor === 1 || userLike.is_distributor === true) {
    return true;
  }
  if (userLike.role === USER_ROLES.DISTRIBUTOR) return true;
  return false;
}

export function isDistributor() {
  let raw = localStorage.getItem('user');
  if (!raw) return false;
  try {
    const user = JSON.parse(raw);
    return userIsDistributorUser(user);
  } catch {
    return false;
  }
}

export function isAdmin() {
  let user = localStorage.getItem('user');
  if (!user) return false;
  user = JSON.parse(user);
  return user.role >= 10;
}

export function isRoot() {
  let user = localStorage.getItem('user');
  if (!user) return false;
  user = JSON.parse(user);
  return user.role >= 100;
}

/** 是否为已通过供应商身份的用户：后端 supplier_id 非 0 */
export function userIsSupplierUser(userLike) {
  if (!userLike || typeof userLike !== 'object') return false;
  const id = userLike.supplier_id;
  return id != null && id !== 0 && id !== '0';
}

export function isSupplier() {
  let raw = localStorage.getItem('user');
  if (!raw) return false;
  try {
    const user = JSON.parse(raw);
    return userIsSupplierUser(user);
  } catch {
    return false;
  }
}

/**
 * 是否可查看首页模型详情中的成本价：供应商、代理商、管理员（role≥10）、超级管理员（role≥100）。
 */
export function userCanViewHomeCostPrice(userLike) {
  if (!userLike || typeof userLike !== 'object') {
    return false;
  }
  if (userIsSupplierUser(userLike)) {
    return true;
  }
  if (userIsDistributorUser(userLike)) {
    return true;
  }
  const role = Number(userLike.role);
  if (!Number.isFinite(role)) {
    return false;
  }
  return role >= 10;
}

/** 分销比例 commission_ratio_bps：后端万分之一单位（1=0.01%），转为百分比展示如 10%、0.01% */
export function formatCommissionRatioPercent(bps) {
  if (bps == null || Number.isNaN(Number(bps))) {
    return '—';
  }
  const n = Number(bps) / 100;
  if (!Number.isFinite(n)) {
    return '—';
  }
  const s = n.toFixed(8).replace(/\.?0+$/, '');
  return `${s}%`;
}

/** 万分之一 bps → 百分比数字字符串（供输入框，如 10、10.5）；0 → '0' */
export function commissionBpsToPercentInputString(bps) {
  if (bps == null || Number(bps) === 0) return '0';
  const n = Number(bps) / 100;
  if (!Number.isFinite(n)) return '0';
  return n.toFixed(8).replace(/\.?0+$/, '');
}

/**
 * 输入框中的百分比（0～100）→ 万分之一 bps。
 * 非法时返回 NaN；空串视为 0。
 */
export function parseCommissionPercentStringToBps(s) {
  const t = String(s ?? '').trim();
  if (t === '' || t === '-') return 0;
  const p = parseFloat(t);
  if (Number.isNaN(p)) return NaN;
  if (p < 0 || p > 100) return NaN;
  return Math.round(p * 100);
}

export function getSystemName() {
  let system_name = localStorage.getItem('system_name');
  if (!system_name) return '词元工厂';
  return system_name;
}

export function getLogo() {
  let logo = localStorage.getItem('logo');
  if (!logo) return '/logo.png';
  return logo;
}

export function getUserIdFromLocalStorage() {
  let user = localStorage.getItem('user');
  if (!user) return -1;
  user = JSON.parse(user);
  return user.id;
}

export function getFooterHTML() {
  return localStorage.getItem('footer_html');
}

export async function copy(text) {
  let okay = true;
  try {
    await navigator.clipboard.writeText(text);
  } catch (e) {
    try {
      // 构建 textarea 执行复制命令，保留多行文本格式
      const textarea = window.document.createElement('textarea');
      textarea.value = text;
      textarea.setAttribute('readonly', '');
      textarea.style.position = 'fixed';
      textarea.style.left = '-9999px';
      textarea.style.top = '-9999px';
      window.document.body.appendChild(textarea);
      textarea.select();
      window.document.execCommand('copy');
      window.document.body.removeChild(textarea);
    } catch (e) {
      okay = false;
      console.error(e);
    }
  }
  return okay;
}

// isMobile 函数已移除，请改用 useIsMobile Hook

let showErrorOptions = { autoClose: toastConstants.ERROR_TIMEOUT };
let showWarningOptions = { autoClose: toastConstants.WARNING_TIMEOUT };
let showSuccessOptions = { autoClose: toastConstants.SUCCESS_TIMEOUT };
let showInfoOptions = { autoClose: toastConstants.INFO_TIMEOUT };
let showNoticeOptions = { autoClose: false };

const isMobileScreen = window.matchMedia(
  `(max-width: ${MOBILE_BREAKPOINT - 1}px)`,
).matches;
if (isMobileScreen) {
  showErrorOptions.position = 'top-center';
  // showErrorOptions.transition = 'flip';

  showSuccessOptions.position = 'top-center';
  // showSuccessOptions.transition = 'flip';

  showInfoOptions.position = 'top-center';
  // showInfoOptions.transition = 'flip';

  showNoticeOptions.position = 'top-center';
  // showNoticeOptions.transition = 'flip';
}

export function showError(error) {
  console.error(error);
  if (error.message) {
    if (error.name === 'AxiosError') {
      switch (error.response.status) {
        case 401:
          // 清除用户状态
          localStorage.removeItem('user');
          // toast.error('错误：未登录或登录已过期，请重新登录！', showErrorOptions);
          window.location.href = '/login?expired=true';
          break;
        case 429:
          Toast.error('错误：请求次数过多，请稍后再试！');
          break;
        case 500:
          Toast.error('错误：服务器内部错误，请联系管理员！');
          break;
        case 405:
          Toast.info('本站仅作演示之用，无服务端！');
          break;
        default:
          Toast.error('错误：' + error.message);
      }
      return;
    }
    Toast.error('错误：' + error.message);
  } else {
    Toast.error('错误：' + error);
  }
}

export function showWarning(message) {
  Toast.warning(message);
}

export function showSuccess(message) {
  Toast.success(message);
}

export function showInfo(message) {
  Toast.info(message);
}

export function showNotice(message, isHTML = false) {
  if (isHTML) {
    toast(<HTMLToastContent htmlContent={message} />, showNoticeOptions);
  } else {
    Toast.info(message);
  }
}

export function openPage(url) {
  window.open(url);
}

export function removeTrailingSlash(url) {
  if (!url) return '';
  if (url.endsWith('/')) {
    return url.slice(0, -1);
  } else {
    return url;
  }
}

export function getTodayStartTimestamp() {
  var now = new Date();
  now.setHours(0, 0, 0, 0);
  return Math.floor(now.getTime() / 1000);
}

export function timestamp2string(timestamp) {
  let date = new Date(timestamp * 1000);
  let year = date.getFullYear().toString();
  let month = (date.getMonth() + 1).toString();
  let day = date.getDate().toString();
  let hour = date.getHours().toString();
  let minute = date.getMinutes().toString();
  let second = date.getSeconds().toString();
  if (month.length === 1) {
    month = '0' + month;
  }
  if (day.length === 1) {
    day = '0' + day;
  }
  if (hour.length === 1) {
    hour = '0' + hour;
  }
  if (minute.length === 1) {
    minute = '0' + minute;
  }
  if (second.length === 1) {
    second = '0' + second;
  }
  return (
    year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second
  );
}

export function timestamp2string1(
  timestamp,
  dataExportDefaultTime = 'hour',
  showYear = false,
) {
  let date = new Date(timestamp * 1000);
  let year = date.getFullYear();
  let month = (date.getMonth() + 1).toString();
  let day = date.getDate().toString();
  let hour = date.getHours().toString();
  if (month.length === 1) {
    month = '0' + month;
  }
  if (day.length === 1) {
    day = '0' + day;
  }
  if (hour.length === 1) {
    hour = '0' + hour;
  }
  // 仅在跨年时显示年份
  let str = showYear ? year + '-' + month + '-' + day : month + '-' + day;
  if (dataExportDefaultTime === 'hour') {
    str += ' ' + hour + ':00';
  } else if (dataExportDefaultTime === 'week') {
    let nextWeek = new Date(timestamp * 1000 + 6 * 24 * 60 * 60 * 1000);
    let nextWeekYear = nextWeek.getFullYear();
    let nextMonth = (nextWeek.getMonth() + 1).toString();
    let nextDay = nextWeek.getDate().toString();
    if (nextMonth.length === 1) {
      nextMonth = '0' + nextMonth;
    }
    if (nextDay.length === 1) {
      nextDay = '0' + nextDay;
    }
    // 周视图结束日期也仅在跨年时显示年份
    let nextStr = showYear
      ? nextWeekYear + '-' + nextMonth + '-' + nextDay
      : nextMonth + '-' + nextDay;
    str += ' - ' + nextStr;
  }
  return str;
}

// 检查时间戳数组是否跨年
export function isDataCrossYear(timestamps) {
  if (!timestamps || timestamps.length === 0) return false;
  const years = new Set(
    timestamps.map((ts) => new Date(ts * 1000).getFullYear()),
  );
  return years.size > 1;
}

export function downloadTextAsFile(text, filename) {
  let blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
  let url = URL.createObjectURL(blob);
  let a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
}

export const verifyJSON = (str) => {
  try {
    JSON.parse(str);
  } catch (e) {
    return false;
  }
  return true;
};

export function verifyJSONPromise(value) {
  try {
    JSON.parse(value);
    return Promise.resolve();
  } catch (e) {
    return Promise.reject('不是合法的 JSON 字符串');
  }
}

export function shouldShowPrompt(id) {
  let prompt = localStorage.getItem(`prompt-${id}`);
  return !prompt;
}

export function setPromptShown(id) {
  localStorage.setItem(`prompt-${id}`, 'true');
}

/**
 * 比较两个对象的属性，找出有变化的属性，并返回包含变化属性信息的数组
 * @param {Object} oldObject - 旧对象
 * @param {Object} newObject - 新对象
 * @return {Array} 包含变化属性信息的数组，每个元素是一个对象，包含 key, oldValue 和 newValue
 */
export function compareObjects(oldObject, newObject) {
  const changedProperties = [];

  // 比较两个对象的属性
  for (const key in oldObject) {
    if (oldObject.hasOwnProperty(key) && newObject.hasOwnProperty(key)) {
      if (oldObject[key] !== newObject[key]) {
        changedProperties.push({
          key: key,
          oldValue: oldObject[key],
          newValue: newObject[key],
        });
      }
    }
  }

  return changedProperties;
}

// playground message

// 生成唯一ID
let messageId = 4;
export const generateMessageId = () => {
  messageId += 1;
  return `${Date.now()}-${messageId}-${Math.random().toString(36).slice(2, 8)}`;
};

// 提取消息中的文本内容
export const getTextContent = (message) => {
  if (!message || !message.content) return '';

  if (Array.isArray(message.content)) {
    const textContent = message.content.find((item) => item.type === 'text');
    return textContent?.text || '';
  }
  return typeof message.content === 'string' ? message.content : '';
};

// 处理 think 标签
export const processThinkTags = (content, reasoningContent = '') => {
  if (!content || !content.includes('<think>')) {
    return { content, reasoningContent };
  }

  const thoughts = [];
  const replyParts = [];
  let lastIndex = 0;
  let match;

  THINK_TAG_REGEX.lastIndex = 0;
  while ((match = THINK_TAG_REGEX.exec(content)) !== null) {
    replyParts.push(content.substring(lastIndex, match.index));
    thoughts.push(match[1]);
    lastIndex = match.index + match[0].length;
  }
  replyParts.push(content.substring(lastIndex));

  const processedContent = replyParts
    .join('')
    .replace(/<\/?think>/g, '')
    .trim();
  const thoughtsStr = thoughts.join('\n\n---\n\n');
  const processedReasoningContent =
    reasoningContent && thoughtsStr
      ? `${reasoningContent}\n\n---\n\n${thoughtsStr}`
      : reasoningContent || thoughtsStr;

  return {
    content: processedContent,
    reasoningContent: processedReasoningContent,
  };
};

// 处理未完成的 think 标签
export const processIncompleteThinkTags = (content, reasoningContent = '') => {
  if (!content) return { content: '', reasoningContent };

  const lastOpenThinkIndex = content.lastIndexOf('<think>');
  if (lastOpenThinkIndex === -1) {
    return processThinkTags(content, reasoningContent);
  }

  const fragmentAfterLastOpen = content.substring(lastOpenThinkIndex);
  if (!fragmentAfterLastOpen.includes('</think>')) {
    const unclosedThought = fragmentAfterLastOpen
      .substring('<think>'.length)
      .trim();
    const cleanContent = content.substring(0, lastOpenThinkIndex);
    const processedReasoningContent = unclosedThought
      ? reasoningContent
        ? `${reasoningContent}\n\n---\n\n${unclosedThought}`
        : unclosedThought
      : reasoningContent;

    return processThinkTags(cleanContent, processedReasoningContent);
  }

  return processThinkTags(content, reasoningContent);
};

// 构建消息内容（包含图片）
export const buildMessageContent = (
  textContent,
  imageUrls = [],
  imageEnabled = false,
) => {
  if (!textContent && (!imageUrls || imageUrls.length === 0)) {
    return '';
  }

  const validImageUrls = imageUrls.filter((url) => url && url.trim() !== '');

  if (imageEnabled && validImageUrls.length > 0) {
    return [
      { type: 'text', text: textContent || '' },
      ...validImageUrls.map((url) => ({
        type: 'image_url',
        image_url: { url: url.trim() },
      })),
    ];
  }

  return textContent || '';
};

// 创建新消息
export const createMessage = (role, content, options = {}) => ({
  role,
  content,
  createAt: Date.now(),
  id: generateMessageId(),
  ...options,
});

// 创建加载中的助手消息
export const createLoadingAssistantMessage = () =>
  createMessage(MESSAGE_ROLES.ASSISTANT, '', {
    reasoningContent: '',
    isReasoningExpanded: true,
    isThinkingComplete: false,
    hasAutoCollapsed: false,
    status: 'loading',
  });

// 检查消息是否包含图片
export const hasImageContent = (message) => {
  return (
    message &&
    Array.isArray(message.content) &&
    message.content.some((item) => item.type === 'image_url')
  );
};

// 格式化消息用于API请求
export const formatMessageForAPI = (message) => {
  if (!message) return null;

  return {
    role: message.role,
    content: message.content,
  };
};

// 验证消息是否有效
export const isValidMessage = (message) => {
  return message && message.role && (message.content || message.content === '');
};

// 获取最后一条用户消息
export const getLastUserMessage = (messages) => {
  if (!Array.isArray(messages)) return null;

  for (let i = messages.length - 1; i >= 0; i--) {
    if (messages[i].role === MESSAGE_ROLES.USER) {
      return messages[i];
    }
  }
  return null;
};

// 获取最后一条助手消息
export const getLastAssistantMessage = (messages) => {
  if (!Array.isArray(messages)) return null;

  for (let i = messages.length - 1; i >= 0; i--) {
    if (messages[i].role === MESSAGE_ROLES.ASSISTANT) {
      return messages[i];
    }
  }
  return null;
};

// 计算相对时间（几天前、几小时前等）
export const getRelativeTime = (publishDate) => {
  if (!publishDate) return '';

  const now = new Date();
  const pubDate = new Date(publishDate);

  // 如果日期无效，返回原始字符串
  if (isNaN(pubDate.getTime())) return publishDate;

  const diffMs = now.getTime() - pubDate.getTime();
  const diffSeconds = Math.floor(diffMs / 1000);
  const diffMinutes = Math.floor(diffSeconds / 60);
  const diffHours = Math.floor(diffMinutes / 60);
  const diffDays = Math.floor(diffHours / 24);
  const diffWeeks = Math.floor(diffDays / 7);
  const diffMonths = Math.floor(diffDays / 30);
  const diffYears = Math.floor(diffDays / 365);

  // 如果是未来时间，显示具体日期
  if (diffMs < 0) {
    return formatDateString(pubDate);
  }

  // 根据时间差返回相应的描述
  if (diffSeconds < 60) {
    return '刚刚';
  } else if (diffMinutes < 60) {
    return `${diffMinutes} 分钟前`;
  } else if (diffHours < 24) {
    return `${diffHours} 小时前`;
  } else if (diffDays < 7) {
    return `${diffDays} 天前`;
  } else if (diffWeeks < 4) {
    return `${diffWeeks} 周前`;
  } else if (diffMonths < 12) {
    return `${diffMonths} 个月前`;
  } else if (diffYears < 2) {
    return '1 年前';
  } else {
    // 超过2年显示具体日期
    return formatDateString(pubDate);
  }
};

// 格式化日期字符串
export const formatDateString = (date) => {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
};

// 格式化日期时间字符串（包含时间）
export const formatDateTimeString = (date) => {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  return `${year}-${month}-${day} ${hours}:${minutes}`;
};

function readTableCompactModes() {
  try {
    const json = localStorage.getItem(TABLE_COMPACT_MODES_KEY);
    return json ? JSON.parse(json) : {};
  } catch {
    return {};
  }
}

function writeTableCompactModes(modes) {
  try {
    localStorage.setItem(TABLE_COMPACT_MODES_KEY, JSON.stringify(modes));
  } catch {
    // ignore
  }
}

export function getTableCompactMode(tableKey = 'global') {
  const modes = readTableCompactModes();
  return !!modes[tableKey];
}

export function setTableCompactMode(compact, tableKey = 'global') {
  const modes = readTableCompactModes();
  modes[tableKey] = compact;
  writeTableCompactModes(modes);
}

// -------------------------------
// Select 组件统一过滤逻辑
// 使用方式： <Select filter={selectFilter} ... />
// 统一的 Select 搜索过滤逻辑 -- 支持同时匹配 option.value 与 option.label
export const selectFilter = (input, option) => {
  if (!input) return true;

  const keyword = input.trim().toLowerCase();
  const valueText = (option?.value ?? '').toString().toLowerCase();
  const labelText = (option?.label ?? '').toString().toLowerCase();

  return valueText.includes(keyword) || labelText.includes(keyword);
};

// -------------------------------
// 模型定价计算工具函数

/** 与后端 ratio_setting.FormatMatchingModelName 一致的模型名规范化 */
export function formatMatchingModelName(name) {
  if (name == null || name === undefined) {
    return '';
  }
  let n = String(name);
  if (n.startsWith('gpt-4-gizmo')) {
    n = 'gpt-4-gizmo-*';
  } else if (n.startsWith('gpt-4o-gizmo')) {
    n = 'gpt-4o-gizmo-*';
  }
  return n;
}

/** 从渠道维度映射读取数值，支持规范化模型名与键名遍历 */
function readChannelScopedModelFloat(byChannel, modelName) {
  if (!byChannel || typeof byChannel !== 'object' || modelName == null) {
    return null;
  }
  const formatted = formatMatchingModelName(modelName);
  const candidates = [modelName, formatted];
  for (const key of candidates) {
    const v = byChannel[key];
    if (typeof v === 'number' && Number.isFinite(v)) {
      return v;
    }
  }
  return null;
}

/** 读取定价接口返回的渠道维度映射：channel_id（字符串）→ model_name → float */
export function pickChannelScopedModelFloat(channelMap, channelId, modelName) {
  if (!channelMap || modelName == null || modelName === undefined) {
    return null;
  }
  const byChannel = channelMap[String(channelId)];
  return readChannelScopedModelFloat(byChannel, modelName);
}

export function getUsedGroupContext(record, selectedGroup, groupRatio) {
  let usedGroup = selectedGroup;
  let usedGroupRatio = groupRatio[selectedGroup];

  if (selectedGroup === 'all' || usedGroupRatio === undefined) {
    let minR = Number.POSITIVE_INFINITY;
    if (
      Array.isArray(record.enable_groups) &&
      record.enable_groups.length > 0
    ) {
      record.enable_groups.forEach((g) => {
        const r = groupRatio[g];
        if (r !== undefined && r < minR) {
          minR = r;
          usedGroup = g;
          usedGroupRatio = r;
        }
      });
    }
    if (usedGroupRatio === undefined) {
      usedGroupRatio = 1;
    }
  }
  return { usedGroup, usedGroupRatio };
}

/** 从多渠道 channel_list 派生 min/max，替代 data 上聚合的 minModelRatio 等字段 */
export function getBoundsFromChannelList(record) {
  const ch = record?.channel_list;
  if (!Array.isArray(ch) || ch.length === 0) {
    return null;
  }
  const pick = (key) =>
    ch.map((c) => Number(c[key])).filter((v) => Number.isFinite(v));
  const ratios = pick('model_ratio');
  const completions = pick('completion_ratio');
  const prices = pick('model_price');
  if (ratios.length === 0) {
    return null;
  }
  return {
    minModelRatio: Math.min(...ratios),
    maxModelRatio: Math.max(...ratios),
    minCompletionRatio:
      completions.length > 0 ? Math.min(...completions) : undefined,
    maxCompletionRatio:
      completions.length > 0 ? Math.max(...completions) : undefined,
    minModelPrice: prices.length > 0 ? Math.min(...prices) : undefined,
    maxModelPrice: prices.length > 0 ? Math.max(...prices) : undefined,
  };
}

export const calculateModelPrice = ({
  record,
  selectedGroup,
  groupRatio,
  groupModelPrice = {},
  groupModelRatio = {},
  tokenUnit,
  displayPrice,
  currency,
  quotaDisplayType = 'USD',
  precision = 2,
}) => {
  const { usedGroup, usedGroupRatio } = getUsedGroupContext(
    record,
    selectedGroup,
    groupRatio,
  );

  const groupPriceMap = groupModelPrice?.[usedGroup] || {};
  const groupRatioMap = groupModelRatio?.[usedGroup] || {};
  const hasGroupModelPrice = Object.prototype.hasOwnProperty.call(
    groupPriceMap,
    record.model_name,
  );
  const hasGroupModelRatio = Object.prototype.hasOwnProperty.call(
    groupRatioMap,
    record.model_name,
  );
  const effectiveModelPrice = hasGroupModelPrice
    ? Number(groupPriceMap[record.model_name])
    : Number(record.model_price);
  const effectiveModelRatio = hasGroupModelRatio
    ? Number(groupRatioMap[record.model_name])
    : Number(record.model_ratio);

  // 2. 根据计费类型计算价格
  if (record.quota_type === 0) {
    // 按量计费：有 channel_list 时以渠道倍率（已含基础×折扣）为基准，再乘分组倍率
    const isTokensDisplay = quotaDisplayType === 'TOKENS';
    const hasChannelPricing =
      Array.isArray(record.channel_list) && record.channel_list.length > 0;
    const chBounds = hasChannelPricing
      ? getBoundsFromChannelList(record)
      : null;

    let minRatio;
    let maxRatio;
    let minCompletionRatio;
    let maxCompletionRatio;

    if (chBounds) {
      minRatio = chBounds.minModelRatio;
      maxRatio = chBounds.maxModelRatio;
      minCompletionRatio =
        chBounds.minCompletionRatio !== undefined
          ? chBounds.minCompletionRatio
          : Number(record.completion_ratio);
      maxCompletionRatio =
        chBounds.maxCompletionRatio !== undefined
          ? chBounds.maxCompletionRatio
          : Number(record.completion_ratio);
    } else {
      minRatio = maxRatio = effectiveModelRatio;
      minCompletionRatio = maxCompletionRatio = Number(record.completion_ratio);
    }

    const hasRange =
      chBounds != null &&
      (minRatio !== maxRatio || minCompletionRatio !== maxCompletionRatio);

    const inputRatioPriceUSD = minRatio * 2 * usedGroupRatio;
    const minInputRatioPriceUSD = minRatio * 2 * usedGroupRatio;
    const maxInputRatioPriceUSD = maxRatio * 2 * usedGroupRatio;

    const unitDivisor = tokenUnit === 'K' ? 1000 : 1;
    const unitLabel = tokenUnit === 'K' ? 'K' : 'M';
    const hasRatioValue = (value) =>
      value !== undefined &&
      value !== null &&
      value !== '' &&
      Number.isFinite(Number(value));

    const formatRatio = (value) =>
      hasRatioValue(value) ? Number(Number(value).toFixed(6)) : null;

    if (isTokensDisplay) {
      const inputRatioForTokens = chBounds ? minRatio : effectiveModelRatio;
      return {
        inputRatio: formatRatio(inputRatioForTokens),
        modelRatioSource: hasGroupModelRatio ? 'group' : 'global',
        completionRatio: formatRatio(record.completion_ratio),
        cacheRatio: formatRatio(record.cache_ratio),
        createCacheRatio: formatRatio(record.create_cache_ratio),
        imageRatio: formatRatio(record.image_ratio),
        audioInputRatio: formatRatio(record.audio_ratio),
        audioOutputRatio: formatRatio(record.audio_completion_ratio),
        isPerToken: true,
        isTokensDisplay: true,
        usedGroup,
        usedGroupRatio,
      };
    }

    let symbol = '$';
    if (currency === 'CNY') {
      symbol = '¥';
    } else if (currency === 'CUSTOM') {
      try {
        const statusStr = localStorage.getItem('status');
        if (statusStr) {
          const s = JSON.parse(statusStr);
          symbol = s?.custom_currency_symbol || '¤';
        } else {
          symbol = '¤';
        }
      } catch (e) {
        symbol = '¤';
      }
    }

    const formatTokenPrice = (priceUSD) => {
      const rawDisplayPrice = displayPrice(priceUSD);
      const numericPrice =
        parseFloat(rawDisplayPrice.replace(/[^0-9.]/g, '')) / unitDivisor;
      return `${symbol}${parseFloat(numericPrice.toFixed(precision))}`;
    };

    const inputPrice = formatTokenPrice(inputRatioPriceUSD);
    const completionSingleRatio = chBounds
      ? minCompletionRatio
      : Number(record.completion_ratio);
    const audioInputPrice = hasRatioValue(record.audio_ratio)
      ? formatTokenPrice(inputRatioPriceUSD * Number(record.audio_ratio))
      : null;

    return {
      inputPrice,
      inputPriceMin: hasRange ? formatTokenPrice(minInputRatioPriceUSD) : null,
      inputPriceMax: hasRange ? formatTokenPrice(maxInputRatioPriceUSD) : null,
      modelRatioSource: hasGroupModelRatio ? 'group' : 'global',
      completionPrice: formatTokenPrice(
        inputRatioPriceUSD * completionSingleRatio,
      ),
      completionPriceMin: hasRange
        ? formatTokenPrice(minInputRatioPriceUSD * minCompletionRatio)
        : null,
      completionPriceMax: hasRange
        ? formatTokenPrice(maxInputRatioPriceUSD * maxCompletionRatio)
        : null,
      cachePrice: hasRatioValue(record.cache_ratio)
        ? formatTokenPrice(inputRatioPriceUSD * Number(record.cache_ratio))
        : null,
      createCachePrice: hasRatioValue(record.create_cache_ratio)
        ? formatTokenPrice(
            inputRatioPriceUSD * Number(record.create_cache_ratio),
          )
        : null,
      imagePrice: hasRatioValue(record.image_ratio)
        ? formatTokenPrice(inputRatioPriceUSD * Number(record.image_ratio))
        : null,
      audioInputPrice,
      audioOutputPrice:
        audioInputPrice && hasRatioValue(record.audio_completion_ratio)
          ? formatTokenPrice(
              inputRatioPriceUSD *
                Number(record.audio_ratio) *
                Number(record.audio_completion_ratio),
            )
          : null,
      unitLabel,
      isPerToken: true,
      isTokensDisplay: false,
      hasRange,
      usedGroup,
      usedGroupRatio,
    };
  }

  if (record.quota_type === 1) {
    // 按次计费
    const priceUSD = effectiveModelPrice * usedGroupRatio;
    const displayVal = displayPrice(priceUSD);

    return {
      price: displayVal,
      modelPriceSource: hasGroupModelPrice ? 'group' : 'global',
      isPerToken: false,
      isTokensDisplay: false,
      usedGroup,
      usedGroupRatio,
    };
  }

  // 未知计费类型，返回占位信息
  return {
    price: '-',
    isPerToken: false,
    isTokensDisplay: false,
    usedGroup,
    usedGroupRatio,
  };
};

// 根据 channel_list 计算并格式化价格范围
export const calculatePriceRange = ({
  record,
  displayPrice,
  currency,
  quotaDisplayType = 'USD',
  precision = 2,
}) => {
  if (!record) {
    return null;
  }
  const b = getBoundsFromChannelList(record);
  if (!b) {
    return null;
  }
  const { minModelPrice, maxModelPrice, minModelRatio, maxModelRatio } = b;
  const { quota_type } = record;

  if (quota_type === 0) {
    // 按量计费 - 使用倍率范围
    if (minModelRatio === undefined || maxModelRatio === undefined) {
      return null;
    }
    const isTokensDisplay = quotaDisplayType === 'TOKENS';
    if (isTokensDisplay) {
      return {
        minRatio: Number(minModelRatio).toFixed(6),
        maxRatio: Number(maxModelRatio).toFixed(6),
        isRange: true,
        isPerToken: true,
      };
    }

    // 价格范围显示
    let symbol = '$';
    if (currency === 'CNY') {
      symbol = '¥';
    } else if (currency === 'CUSTOM') {
      try {
        const statusStr = localStorage.getItem('status');
        if (statusStr) {
          const s = JSON.parse(statusStr);
          symbol = s?.custom_currency_symbol || '¤';
        } else {
          symbol = '¤';
        }
      } catch (e) {
        symbol = '¤';
      }
    }

    const minPriceUSD = minModelRatio * 2;
    const maxPriceUSD = maxModelRatio * 2;
    const minDisplay = displayPrice(minPriceUSD);
    const maxDisplay = displayPrice(maxPriceUSD);

    return {
      minPrice: minDisplay,
      maxPrice: maxDisplay,
      isRange: true,
      isPerToken: true,
    };
  } else if (quota_type === 1) {
    // 按次计费 - 使用价格范围
    if (minModelPrice === undefined || maxModelPrice === undefined) {
      return null;
    }
    const minDisplay = displayPrice(minModelPrice);
    const maxDisplay = displayPrice(maxModelPrice);
    return {
      minPrice: minDisplay,
      maxPrice: maxDisplay,
      isRange: true,
      isPerToken: false,
    };
  }

  return null;
};

export const getModelPriceItems = (priceData, t, quotaDisplayType = 'USD') => {
  if (priceData.isPerToken) {
    if (quotaDisplayType === 'TOKENS' || priceData.isTokensDisplay) {
      return [
        {
          key: 'input-ratio',
          label: t('输入倍率'),
          value: priceData.inputRatio,
          suffix: 'x',
        },
        {
          key: 'completion-ratio',
          label: t('输出倍率'),
          value: priceData.completionRatio,
          suffix: 'x',
        },
        {
          key: 'cache-ratio',
          label: t('缓存读取倍率'),
          value: priceData.cacheRatio,
          suffix: 'x',
        },
        {
          key: 'create-cache-ratio',
          label: t('缓存创建倍率'),
          value: priceData.createCacheRatio,
          suffix: 'x',
        },
        {
          key: 'image-ratio',
          label: t('图片输入倍率'),
          value: priceData.imageRatio,
          suffix: 'x',
        },
        {
          key: 'audio-input-ratio',
          label: t('音频输入倍率'),
          value: priceData.audioInputRatio,
          suffix: 'x',
        },
        {
          key: 'audio-output-ratio',
          label: t('音频输出倍率'),
          value: priceData.audioOutputRatio,
          suffix: 'x',
        },
      ].filter(
        (item) =>
          item.value !== null && item.value !== undefined && item.value !== '',
      );
    }

    const unitSuffix = ` / 1${priceData.unitLabel} Tokens`;

    // 格式化价格显示，支持范围
    const formatPriceValue = (price, minPrice, maxPrice) => {
      if (priceData.hasRange && minPrice && maxPrice && minPrice !== maxPrice) {
        return `${minPrice} ~ ${maxPrice}`;
      }
      return price;
    };

    return [
      {
        key: 'input',
        label: t('输入价格'),
        value: formatPriceValue(
          priceData.inputPrice,
          priceData.inputPriceMin,
          priceData.inputPriceMax,
        ),
        suffix: unitSuffix,
      },
      {
        key: 'completion',
        label: t('输出价格'),
        value: formatPriceValue(
          priceData.completionPrice,
          priceData.completionPriceMin,
          priceData.completionPriceMax,
        ),
        suffix: unitSuffix,
      },
      {
        key: 'image',
        label: t('图片输入价格'),
        value: priceData.imagePrice,
        suffix: unitSuffix,
      },
      {
        key: 'audio-input',
        label: t('音频输入价格'),
        value: priceData.audioInputPrice,
        suffix: unitSuffix,
      },
      {
        key: 'audio-output',
        label: t('音频输出价格'),
        value: priceData.audioOutputPrice,
        suffix: unitSuffix,
      },
    ].filter(
      (item) =>
        item.value !== null && item.value !== undefined && item.value !== '',
    );
  }

  return [
    {
      key: 'fixed',
      label: t('模型价格'),
      value: priceData.price,
      suffix: ` / ${t('次')}`,
    },
  ].filter(
    (item) =>
      item.value !== null && item.value !== undefined && item.value !== '',
  );
};

// 格式化价格信息（用于卡片视图）
export const formatPriceInfo = (priceData, t, quotaDisplayType = 'USD') => {
  const items = getModelPriceItems(priceData, t, quotaDisplayType);
  return (
    <>
      {items.map((item) => (
        <span key={item.key} style={{ color: 'var(--semi-color-text-1)' }}>
          {item.label} {item.value}
          {item.suffix}
        </span>
      ))}
    </>
  );
};

// -------------------------------
// CardPro 分页配置函数
// 用于创建 CardPro 的 paginationArea 配置
export const createCardProPagination = ({
  currentPage,
  pageSize,
  total,
  onPageChange,
  onPageSizeChange,
  isMobile = false,
  pageSizeOpts = [10, 20, 50, 100],
  showSizeChanger = true,
  t = (key) => key,
}) => {
  if (!total || total <= 0) return null;

  const start = (currentPage - 1) * pageSize + 1;
  const end = Math.min(currentPage * pageSize, total);
  const totalText = `${t('显示第')} ${start} ${t('条 - 第')} ${end} ${t('条，共')} ${total} ${t('条')}`;

  return (
    <>
      {/* 桌面端左侧总数信息 */}
      {!isMobile && (
        <span
          className='text-sm select-none'
          style={{ color: 'var(--semi-color-text-2)' }}
        >
          {totalText}
        </span>
      )}

      {/* 右侧分页控件 */}
      <Pagination
        currentPage={currentPage}
        pageSize={pageSize}
        total={total}
        pageSizeOpts={pageSizeOpts}
        showSizeChanger={showSizeChanger}
        onPageSizeChange={onPageSizeChange}
        onPageChange={onPageChange}
        size={isMobile ? 'small' : 'default'}
        showQuickJumper={isMobile}
        showTotal
      />
    </>
  );
};

// 模型定价筛选条件默认值
const DEFAULT_PRICING_FILTERS = {
  search: '',
  showWithRecharge: false,
  currency: 'USD',
  showRatio: false,
  viewMode: 'card',
  tokenUnit: 'M',
  filterGroup: 'all',
  filterQuotaType: 'all',
  filterEndpointType: 'all',
  filterVendor: 'all',
  filterTag: 'all',
  filterSupplierType: 'all',
  currentPage: 1,
};

// 重置模型定价筛选条件
export const resetPricingFilters = ({
  handleChange,
  setShowWithRecharge,
  setCurrency,
  setShowRatio,
  setViewMode,
  setFilterGroup,
  setFilterQuotaType,
  setFilterEndpointType,
  setFilterVendor,
  setFilterTag,
  setFilterSupplierType,
  setFilterSupplier,
  setCurrentPage,
  setTokenUnit,
}) => {
  handleChange?.(DEFAULT_PRICING_FILTERS.search);
  setShowWithRecharge?.(DEFAULT_PRICING_FILTERS.showWithRecharge);
  setCurrency?.(DEFAULT_PRICING_FILTERS.currency);
  setShowRatio?.(DEFAULT_PRICING_FILTERS.showRatio);
  setViewMode?.(DEFAULT_PRICING_FILTERS.viewMode);
  setTokenUnit?.(DEFAULT_PRICING_FILTERS.tokenUnit);
  setFilterGroup?.(DEFAULT_PRICING_FILTERS.filterGroup);
  setFilterQuotaType?.(DEFAULT_PRICING_FILTERS.filterQuotaType);
  setFilterEndpointType?.(DEFAULT_PRICING_FILTERS.filterEndpointType);
  setFilterVendor?.(DEFAULT_PRICING_FILTERS.filterVendor);
  setFilterTag?.(DEFAULT_PRICING_FILTERS.filterTag);
  setFilterSupplierType?.(DEFAULT_PRICING_FILTERS.filterSupplierType);
  setFilterSupplier?.('all');
  setCurrentPage?.(DEFAULT_PRICING_FILTERS.currentPage);
};
