import { useMemo, useState, type ReactNode } from 'react';
import { ListChecks, Plus, Trash2 } from 'lucide-react';
import type { PricingRuleInput } from '@easyai-ai-gateway/contracts';
import { Badge, Button, Input, Label, Select } from '../../components/ui';
import { cn } from '../../lib/utils';
import { calculatorLabel, PricingFormulaNote, unitLabel } from './PricingEditorControls';

type RecordValue = Record<string, unknown>;
type ModeKey = 'text' | 'image' | 'video';
type ParameterGroup = {
  key: string;
  title: string;
  defaults: RecordValue;
  labels?: Record<string, string>;
  locked?: boolean;
};

type ModeDefinition = {
  key: ModeKey;
  label: string;
  formula: string;
  match: (rule: PricingRuleInput) => boolean;
  templates: (currency: string) => PricingRuleInput[];
  parameterGroups: ParameterGroup[];
};

const statuses = ['active', 'deprecated', 'hidden'];

const modeDefinitions: ModeDefinition[] = [
  {
    key: 'text',
    label: '文本',
    formula:
      '一次对话扣费 = 未命中缓存输入 Token / 1000 × 输入扣费单价 + 命中缓存输入 Token / 1000 × 缓存输入扣费单价 + 输出 Token / 1000 × 输出扣费单价。',
    match: isTextPricingRule,
    templates: (currency) => [createTextRule(currency, 0.01, 0.01, 0.03)],
    parameterGroups: [],
  },
  {
    key: 'image',
    label: '图像',
    formula: '扣费 = 基础单价 × 数量 × 分辨率参数 × 图像质量参数。图像质量按 OpenAI GPT Image 的 low / medium / high 三档配置。',
    match: (rule) => rule.resourceType === 'image' || rule.resourceType === 'image_edit',
    templates: (currency) => [createRule('image', '图像', 'image', 'image', 10, currency, 'unit_weight', 'count * base_price * resolution_factor * quality_factor', {
        resolutionFactors: { '1K': 1, '2K': 1.5, '3K': 1.75, '4K': 2, '8K': 4 },
        qualityFactors: { low: 0.5, medium: 1, high: 1.5 },
      }, { dimensions: ['count', 'resolution', 'quality'], defaults: { count: 1, resolution: '1K', quality: 'medium' } })],
    parameterGroups: [
      { key: 'resolutionFactors', title: '分辨率', defaults: { '1K': 1, '2K': 1.5, '3K': 1.75, '4K': 2, '8K': 4 }, locked: true },
      { key: 'qualityFactors', title: '图像质量', defaults: { low: 0.5, medium: 1, high: 1.5 }, labels: { low: '低质量 (low)', medium: '标准质量 (medium)', high: '高质量 (high)' }, locked: true },
    ],
  },
  {
    key: 'video',
    label: '视频',
    formula: '扣费 = 基础单价 × 生成时长单位 × 数量 × 分辨率、音频、参考视频、音色等计费参数。',
    match: (rule) => rule.resourceType === 'video',
    templates: (currency) => [
      createRule('video', '视频', 'video', '5s', 100, currency, 'duration_weight', 'count * (duration_seconds / 5) * base_price * resolution_factor * audio_factor * reference_video_factor * voice_specified_factor', {
        resolutionWeights: { '480p': 0.75, '720p': 1, '1080p': 1.5, '2160p': 2 },
        audioWeights: { true: 2, false: 1 },
        referenceVideoWeights: { true: 1.5, false: 1 },
        voiceSpecifiedWeights: { true: 1.2, false: 1 },
      }, { dimensions: ['count', 'duration_seconds', 'resolution', 'audio', 'reference_video', 'voice_specified'], defaults: { count: 1, duration_seconds: 5, resolution: '720p', audio: false, reference_video: false, voice_specified: false } }),
    ],
    parameterGroups: [
      { key: 'resolutionWeights', title: '分辨率', defaults: { '480p': 0.75, '720p': 1, '1080p': 1.5, '2160p': 2 }, locked: true },
      { key: 'audioWeights', title: '生成声音', defaults: { true: 2, false: 1 }, labels: { true: '生成声音', false: '不生成声音' }, locked: true },
      { key: 'referenceVideoWeights', title: '参考视频', defaults: { true: 1.5, false: 1 }, labels: { true: '有参考视频', false: '无参考视频' }, locked: true },
      { key: 'voiceSpecifiedWeights', title: '指定音色', defaults: { true: 1.2, false: 1 }, labels: { true: '指定音色', false: '不指定音色' }, locked: true },
    ],
  },
];

export function PricingRuleVisualEditor(props: {
  currency: string;
  rules: PricingRuleInput[];
  onChange: (rules: PricingRuleInput[]) => void;
}) {
  const [activeMode, setActiveMode] = useState<ModeKey>('text');
  const mode = modeDefinitions.find((item) => item.key === activeMode) ?? modeDefinitions[0];
  const rawActiveRules = useMemo(() => props.rules.filter(mode.match), [mode, props.rules]);
  const activeRules = useMemo(() => {
    if (mode.key === 'text' && rawActiveRules.length) return [completeRule(mergeTextRules(rawActiveRules, props.currency), mode)];
    if (mode.key === 'image' && rawActiveRules.length) return [completeRule(mergeTemplateRules(mode.templates(props.currency), rawActiveRules)[0], mode)];
    return rawActiveRules.map((rule) => completeRule(rule, mode));
  }, [mode.key, props.currency, rawActiveRules]);
  const modeCounts = useMemo(() => modeRuleCounts(props.rules), [props.rules]);
  const modeSummary = useMemo(() => summarizePricingMode(mode, activeRules), [activeRules, mode]);

  function replaceModeRules(nextRules: PricingRuleInput[]) {
    props.onChange([...props.rules.filter((rule) => !mode.match(rule)), ...nextRules]);
  }

  return (
    <section className="pricingModeEditor spanTwo">
      <div className="pricingModeHeader">
        <div>
          <strong>计费模式</strong>
          <span>选择能力后维护基础价格、计费公式和计费参数。</span>
        </div>
      </div>

      <div className="pricingModeWorkbench">
        <aside className="pricingModeSidebar">
          <div className="pricingModeSidebarTitle">
            <ListChecks size={15} />
            <strong>计费模式</strong>
          </div>
          <div className="pricingModeList">
            {modeDefinitions.map((item) => (
              <button data-active={item.key === activeMode} key={item.key} type="button" onClick={() => setActiveMode(item.key)}>
                <span>
                  <strong>{item.label}</strong>
                  <small>{modeCounts[item.key] ?? 0} 条计价规则</small>
                </span>
              </button>
            ))}
          </div>
          <div className="pricingModeSummary">
            <strong>规则总结</strong>
            <p>{modeSummary}</p>
          </div>
        </aside>

        <div className="pricingModePanel">
          {activeRules.length ? (
            activeRules.map((rule, index) => (
              <ModeRuleEditor
                key={`${rule.ruleKey ?? rule.resourceType}-${index}`}
                mode={mode}
                rule={rule}
                onChange={(nextRule) => replaceModeRules(activeRules.map((item, itemIndex) => (itemIndex === index ? nextRule : item)))}
                onDelete={() => replaceModeRules(activeRules.filter((_, itemIndex) => itemIndex !== index))}
              />
            ))
          ) : (
            <div className="pricingModeEmpty">
              <strong>{mode.label} 还没有计价配置</strong>
              <Button type="button" onClick={() => replaceModeRules(mode.templates(props.currency))}><Plus size={15} />添加默认配置</Button>
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

export function createDefaultPricingRules(currency: string): PricingRuleInput[] {
  return modeDefinitions.flatMap((mode) => mode.templates(currency).map((rule) => completeRule(rule, mode)));
}

function modeRuleCounts(rules: PricingRuleInput[]): Record<ModeKey, number> {
  return Object.fromEntries(
    modeDefinitions.map((mode) => [mode.key, mode.key === 'text' && rules.some(mode.match) ? 1 : rules.filter(mode.match).length]),
  ) as Record<ModeKey, number>;
}

function summarizePricingMode(mode: ModeDefinition, rules: PricingRuleInput[]) {
  if (!rules.length) return `${mode.label}暂无计价配置，可一键添加默认规则。`;
  const rule = rules[0];
  if (mode.key === 'text') {
    const prices = textPrices(rule);
    return `文本按输入/缓存输入/输出 Token 分别计费，输入 ${prices.inputTokenPrice}/${unitLabel(rule.unit)}，缓存输入 ${prices.cachedInputTokenPrice}/${unitLabel(rule.unit)}，输出 ${prices.outputTokenPrice}/${unitLabel(rule.unit)}。`;
  }
  const groupSummaries = mode.parameterGroups
    .map((group) => summarizeWeightGroup(group, readGroup(rule.dynamicWeight, group)))
    .filter(Boolean);
  const details = groupSummaries.length ? `\n${groupSummaries.join('\n')}` : '';
  return `${mode.label}按 ${unitLabel(rule.unit)} 计费，基础单价 ${rule.basePrice}，计算方式为${calculatorLabel(rule.calculatorType)}${details}。`;
}

function summarizeWeightGroup(group: ParameterGroup, value: RecordValue) {
  const items = Object.entries(value)
    .map(([key, weight]) => `${summaryWeightLabel(group, key)} ×${scalarToString(weight)}`)
    .join('、');
  return items ? `${group.title}：${items}` : '';
}

function summaryWeightLabel(group: ParameterGroup, key: string) {
  const label = group.labels?.[key] ?? key;
  return label.replace(/\s*\([^)]*\)\s*$/, '');
}

function ModeRuleEditor(props: {
  mode: ModeDefinition;
  rule: PricingRuleInput;
  onChange: (rule: PricingRuleInput) => void;
  onDelete: () => void;
}) {
  const rule = props.rule;

  function patch(patchValue: Partial<PricingRuleInput>) {
    props.onChange(completeRule({ ...rule, ...patchValue }, props.mode));
  }

  function patchDynamicWeight(key: string, value: RecordValue) {
    patch({ dynamicWeight: { ...(rule.dynamicWeight ?? {}), [key]: value } });
  }

  if (props.mode.key === 'text') {
    return <TextRuleEditor formula={props.mode.formula} rule={rule} onChange={props.onChange} onDelete={props.onDelete} />;
  }

  return (
    <article className="pricingModeRule">
      <header>
        <div>
          <Badge variant="secondary">{rule.resourceType}</Badge>
          <strong>{rule.displayName || props.mode.label}</strong>
          <span>{rule.ruleKey}</span>
        </div>
        <Button type="button" variant="ghost" size="sm" onClick={props.onDelete}><Trash2 size={14} />删除</Button>
      </header>

      <PricingFormRows>
        <PricingFormRow label="展示名称">
          <Input size="sm" value={rule.displayName ?? ''} onChange={(event) => patch({ displayName: event.target.value })} />
        </PricingFormRow>
        <PricingFormRow label="状态">
          <Select size="sm" value={rule.status ?? 'active'} onChange={(event) => patch({ status: event.target.value })}>{statuses.map((item) => <option key={item} value={item}>{item}</option>)}</Select>
        </PricingFormRow>
        <PricingFormRow label={`基础单价/${unitLabel(rule.unit)}`}>
          <Input disabled={rule.isFree} size="sm" min="0" step="0.000000001" type="number" value={rule.basePrice} onChange={(event) => patch({ basePrice: Number(event.target.value) })} />
        </PricingFormRow>
        <PricingFormRow label="显式免费">
          <label>
            <input
              type="checkbox"
              checked={rule.isFree ?? false}
              onChange={(event) => patch({ isFree: event.target.checked, basePrice: event.target.checked ? 0 : rule.basePrice })}
            />
            <span>允许该规则以零费用运行</span>
          </label>
        </PricingFormRow>
        <PricingReadonlyRow label="计价单位" value={unitLabel(rule.unit)} />
        <PricingReadonlyRow label="计算方式" value={calculatorLabel(rule.calculatorType)} />
      </PricingFormRows>

      <PricingFormulaNote>{props.mode.formula}</PricingFormulaNote>

      <div className="pricingWeightStack">
        {props.mode.parameterGroups.map((group) => (
          <WeightTable
            key={group.key}
            title={group.title}
            value={readGroup(rule.dynamicWeight, group)}
            labels={group.labels}
            locked={group.locked}
            onChange={(value) => patchDynamicWeight(group.key, value)}
          />
        ))}
        {Object.entries(rule.dynamicWeight ?? {}).filter(([key]) => !props.mode.parameterGroups.some((group) => group.key === key)).map(([key, value]) => (
          <WeightTable key={key} editableTitle title={key} value={isPlainObject(value) ? value as RecordValue : { value }} onChange={(nextValue, nextTitle) => {
            const dynamicWeight = { ...(rule.dynamicWeight ?? {}) };
            delete dynamicWeight[key];
            dynamicWeight[nextTitle || key] = nextValue;
            patch({ dynamicWeight });
          }} />
        ))}
      </div>
    </article>
  );
}

function TextRuleEditor(props: {
  formula: string;
  rule: PricingRuleInput;
  onChange: (rule: PricingRuleInput) => void;
  onDelete: () => void;
}) {
  const prices = textPrices(props.rule);

  function updatePrices(
    inputTokenPrice: number,
    cachedInputTokenPrice: number,
    outputTokenPrice: number,
  ) {
    props.onChange({
      ...props.rule,
      basePrice: inputTokenPrice,
      displayName: props.rule.displayName || '文本',
      resourceType: 'text_total',
      ruleKey: 'text',
      unit: '1k_tokens',
      formulaConfig: {
        ...(props.rule.formulaConfig ?? {}),
        formula: textFormula,
        inputTokenPrice,
        cachedInputTokenPrice,
        outputTokenPrice,
      },
      dimensionSchema: {
        ...(props.rule.dimensionSchema ?? {}),
        metrics: [
          'input_tokens',
          'uncached_input_tokens',
          'cached_input_tokens',
          'output_tokens',
        ],
        unitScale: 1000,
      },
    });
  }

  return (
    <article className="pricingModeRule pricingTextRule">
      <header>
        <div>
          <Badge variant="secondary">text_total</Badge>
          <strong>{props.rule.displayName || '文本'}</strong>
          <span>text</span>
        </div>
        <Button type="button" variant="ghost" size="sm" onClick={props.onDelete}><Trash2 size={14} />删除</Button>
      </header>

      <PricingFormRows>
        <PricingFormRow label="展示名称">
          <Input size="sm" value={props.rule.displayName ?? '文本'} onChange={(event) => props.onChange({ ...props.rule, displayName: event.target.value, ruleKey: 'text' })} />
        </PricingFormRow>
        <PricingFormRow label="状态">
          <Select size="sm" value={props.rule.status ?? 'active'} onChange={(event) => props.onChange({ ...props.rule, status: event.target.value })}>{statuses.map((item) => <option key={item} value={item}>{item}</option>)}</Select>
        </PricingFormRow>
        <PricingFormRow label="显式免费">
          <label>
            <input
              type="checkbox"
              checked={props.rule.isFree ?? false}
              onChange={(event) => {
                const isFree = event.target.checked;
                props.onChange({
                  ...props.rule,
                  isFree,
                  basePrice: isFree ? 0 : props.rule.basePrice,
                  formulaConfig: isFree
                    ? { ...(props.rule.formulaConfig ?? {}), inputTokenPrice: 0, cachedInputTokenPrice: 0, outputTokenPrice: 0 }
                    : props.rule.formulaConfig,
                });
              }}
            />
            <span>允许该规则以零费用运行</span>
          </label>
        </PricingFormRow>
        <PricingFormRow label="输入单价/1K tokens">
          <Input
            disabled={props.rule.isFree}
            size="sm"
            min="0"
            step="0.000000001"
            type="number"
            value={prices.inputTokenPrice}
            onChange={(event) =>
              updatePrices(
                Number(event.target.value),
                prices.cachedInputTokenPrice,
                prices.outputTokenPrice,
              )
            }
          />
        </PricingFormRow>
        <PricingFormRow label="缓存输入单价/1K tokens">
          <Input
            disabled={props.rule.isFree}
            size="sm"
            min="0"
            step="0.000000001"
            type="number"
            value={prices.cachedInputTokenPrice}
            onChange={(event) =>
              updatePrices(
                prices.inputTokenPrice,
                Number(event.target.value),
                prices.outputTokenPrice,
              )
            }
          />
        </PricingFormRow>
        <PricingFormRow label="输出单价/1K tokens">
          <Input
            disabled={props.rule.isFree}
            size="sm"
            min="0"
            step="0.000000001"
            type="number"
            value={prices.outputTokenPrice}
            onChange={(event) =>
              updatePrices(
                prices.inputTokenPrice,
                prices.cachedInputTokenPrice,
                Number(event.target.value),
              )
            }
          />
        </PricingFormRow>
        <PricingReadonlyRow label="计价单位" value={unitLabel(props.rule.unit)} />
        <PricingReadonlyRow label="计算方式" value={calculatorLabel(props.rule.calculatorType)} />
      </PricingFormRows>

      <PricingFormulaNote>{props.formula}</PricingFormulaNote>
    </article>
  );
}

function PricingFormRows(props: { children: ReactNode }) {
  return <div className="pricingFormRows">{props.children}</div>;
}

function PricingFormRow(props: { children: ReactNode; label: string }) {
  return (
    <div className="pricingFormRow">
      <strong>{props.label}</strong>
      {props.children}
    </div>
  );
}

function PricingReadonlyRow(props: { label: string; value: string }) {
  return (
    <div className="pricingFormRow">
      <strong>{props.label}</strong>
      <span className="pricingFormReadonly">{props.value}</span>
    </div>
  );
}

function WeightTable(props: {
  editableTitle?: boolean;
  labels?: Record<string, string>;
  locked?: boolean;
  title: string;
  value: RecordValue;
  onChange: (value: RecordValue, title?: string) => void;
}) {
  const rows: Array<[string, unknown]> = Object.entries(props.value ?? {});

  function updateRows(nextRows: Array<[string, unknown]>) {
    props.onChange(rowsToRecord(nextRows), props.title);
  }

  return (
    <section className="pricingWeightTable">
      <header>
        {props.editableTitle ? (
          <Input value={props.title} onChange={(event) => props.onChange(props.value, event.target.value)} />
        ) : (
          <strong>{props.title}</strong>
        )}
      </header>
      <div className="pricingWeightRows">
        {rows.map(([key, value], index) => (
          <div className={cn('pricingWeightRow', props.locked && 'locked')} key={`${key}-${index}`}>
            {props.locked ? (
              <span className="pricingFactorLabel">{props.labels?.[key] ?? key}</span>
            ) : (
              <Input value={key} onChange={(event) => updateRows(rows.map((row, rowIndex) => (rowIndex === index ? [event.target.value, value] : row)))} />
            )}
            <Input value={scalarToString(value)} onChange={(event) => updateRows(rows.map((row, rowIndex) => (rowIndex === index ? [key, parseScalar(event.target.value)] : row)))} />
            {!props.locked && <Button type="button" variant="ghost" size="icon" onClick={() => updateRows(rows.filter((_, rowIndex) => rowIndex !== index))}><Trash2 size={14} /></Button>}
          </div>
        ))}
        {!props.locked && <Button className="pricingInlineAdd" type="button" variant="outline" size="sm" onClick={() => updateRows([...rows, [nextKey(props.value, 'option'), 1]])}><Plus size={14} />添加</Button>}
      </div>
    </section>
  );
}

export function KeyValueEditor(props: {
  className?: string;
  title: string;
  value: RecordValue;
  onChange: (value: RecordValue) => void;
}) {
  return (
    <div className={cn('pricingWeightTable', props.className)}>
      <header><strong>{props.title}</strong></header>
      <WeightTable title={props.title} value={props.value} onChange={props.onChange} />
    </div>
  );
}

function completeRule(rule: PricingRuleInput, mode: ModeDefinition): PricingRuleInput {
  const template = mode.templates(rule.currency ?? 'resource')[0] ?? rule;
  return {
    ...template,
    ...rule,
    ruleKey: mode.key,
    displayName: normalizeDisplayName(rule.displayName || template.displayName, mode),
    resourceType: template.resourceType,
    dimensionSchema: template.dimensionSchema,
    formulaConfig: {
      ...(rule.formulaConfig ?? {}),
      formula: template.formulaConfig?.formula,
    },
    dynamicWeight: normalizeDynamicWeight(rule.dynamicWeight, mode),
  };
}

function normalizeDisplayName(value: string | undefined, mode: ModeDefinition) {
  const legacyNames: Record<ModeKey, string[]> = {
    text: ['文本输入 Token', '文本输出 Token', '文本生成 Token', '文本生成'],
    image: ['图像生成', '图像编辑'],
    video: ['视频生成'],
  };
  if (!value || legacyNames[mode.key].includes(value)) return mode.label;
  return value;
}

function normalizeDynamicWeight(value: PricingRuleInput['dynamicWeight'], mode: ModeDefinition): RecordValue {
  const source = isPlainObject(value) ? { ...(value as RecordValue) } : {};
  if (mode.key === 'image') {
    if (!isPlainObject(source.resolutionFactors) && isPlainObject(source.resolutionWeights)) {
      source.resolutionFactors = source.resolutionWeights;
    }
    if (!isPlainObject(source.qualityFactors) && isPlainObject(source.qualityWeights)) {
      source.qualityFactors = source.qualityWeights;
    }
    delete source.modeFactors;
    delete source.modeWeights;
    delete source.referenceImageWeights;
    delete source.resolutionWeights;
    delete source.qualityWeights;
  }

  const groupKeys = new Set(mode.parameterGroups.map((group) => group.key));
  const defaults = Object.fromEntries(mode.parameterGroups.map((group) => [
    group.key,
    mergeGroupDefaults(group, isPlainObject(source[group.key]) ? source[group.key] as RecordValue : {}),
  ]));
  const custom = Object.fromEntries(Object.entries(source).filter(([key]) => !groupKeys.has(key)));
  return { ...defaults, ...custom };
}

function mergeGroupDefaults(group: ParameterGroup, source: RecordValue): RecordValue {
  if (!group.locked) return { ...group.defaults, ...source };
  return Object.fromEntries(Object.entries(group.defaults).map(([key, defaultValue]) => [
    key,
    key in source ? source[key] : defaultValue,
  ]));
}

function mergeTemplateRules(templates: PricingRuleInput[], rules: PricingRuleInput[]) {
  if (templates.length === 1) return rules.length ? [{ ...templates[0], ...rules[0] }] : templates;
  const byKey = new Map(templates.map((rule) => [rule.ruleKey ?? rule.resourceType, rule]));
  for (const rule of rules) {
    byKey.set(rule.ruleKey ?? rule.resourceType, rule);
  }
  return Array.from(byKey.values());
}

function mergeTextRules(rules: PricingRuleInput[], currency: string): PricingRuleInput {
  const totalRule = rules.find((rule) => rule.resourceType === 'text_total' || rule.resourceType === 'text' || rule.ruleKey === 'text');
  const inputRule = rules.find((rule) => rule.resourceType === 'text_input');
  const cachedInputRule = rules.find(
    (rule) => rule.resourceType === 'text_cached_input',
  );
  const outputRule = rules.find((rule) => rule.resourceType === 'text_output');
  const source =
    totalRule ??
    inputRule ??
    cachedInputRule ??
    outputRule ??
    createTextRule(currency, 0.01, 0.01, 0.03);
  return createTextRule(
    source.currency ?? currency,
    Number(
      source.formulaConfig?.inputTokenPrice ??
        inputRule?.basePrice ??
        source.basePrice ??
        0.01,
    ),
    Number(
      source.formulaConfig?.cachedInputTokenPrice ??
        source.formulaConfig?.inputCacheHitTokenPrice ??
        cachedInputRule?.basePrice ??
        source.formulaConfig?.inputTokenPrice ??
        inputRule?.basePrice ??
        source.basePrice ??
        0.01,
    ),
    Number(
      source.formulaConfig?.outputTokenPrice ?? outputRule?.basePrice ?? 0.03,
    ),
    source,
  );
}

function readGroup(value: RecordValue | undefined, group: ModeDefinition['parameterGroups'][number]) {
  return isPlainObject(value?.[group.key]) ? value?.[group.key] as RecordValue : group.defaults;
}

const textFormula =
  'uncached_input_tokens / 1000 * input_token_price + cached_input_tokens / 1000 * cached_input_token_price + output_tokens / 1000 * output_token_price';

function createTextRule(
  currency: string,
  inputTokenPrice: number,
  cachedInputTokenPrice: number,
  outputTokenPrice: number,
  source?: PricingRuleInput,
): PricingRuleInput {
  return {
    ...(source ?? {}),
    ruleKey: 'text',
    displayName: normalizeDisplayName(source?.displayName, modeDefinitions[0]),
    resourceType: 'text_total',
    unit: '1k_tokens',
    basePrice: inputTokenPrice,
    currency,
    calculatorType: 'token_usage',
    baseWeight: {},
    dynamicWeight: {},
    dimensionSchema: {
      metrics: [
        'input_tokens',
        'uncached_input_tokens',
        'cached_input_tokens',
        'output_tokens',
      ],
      unitScale: 1000,
      ...(source?.dimensionSchema ?? {}),
    },
    formulaConfig: {
      ...(source?.formulaConfig ?? {}),
      formula: textFormula,
      inputTokenPrice,
      cachedInputTokenPrice,
      outputTokenPrice,
    },
    priority: source?.priority ?? 100,
    status: source?.status ?? 'active',
    metadata: source?.metadata ?? {},
  };
}

function textPrices(rule: PricingRuleInput) {
  const compatRule = rule as PricingRuleInput & {
    cachedInputTokenPrice?: number;
    inputCacheHitTokenPrice?: number;
    inputTokenPrice?: number;
    outputTokenPrice?: number;
  };
  const inputTokenPrice = Number(
    rule.formulaConfig?.inputTokenPrice ?? compatRule.inputTokenPrice ?? rule.basePrice ?? 0.01,
  );
  return {
    inputTokenPrice,
    cachedInputTokenPrice: Number(
      rule.formulaConfig?.cachedInputTokenPrice ??
        rule.formulaConfig?.inputCacheHitTokenPrice ??
        compatRule.cachedInputTokenPrice ??
        compatRule.inputCacheHitTokenPrice ??
        inputTokenPrice,
    ),
    outputTokenPrice: Number(rule.formulaConfig?.outputTokenPrice ?? compatRule.outputTokenPrice ?? 0.03),
  };
}

function isTextPricingRule(rule: PricingRuleInput) {
  const resourceType = String(rule.resourceType ?? '');
  const ruleKey = String(rule.ruleKey ?? '');
  return textPricingKeys.has(resourceType) || textPricingKeys.has(ruleKey);
}

const textPricingKeys = new Set(['text', 'text_total', 'text_input', 'text_cached_input', 'text_output']);

function createRule(ruleKey: string, displayName: string, resourceType: string, unit: string, basePrice: number, currency: string, calculatorType: string, formula: string, dynamicWeight: RecordValue, dimensionSchema: RecordValue): PricingRuleInput {
  return {
    ruleKey,
    displayName,
    resourceType,
    unit,
    basePrice,
    currency,
    calculatorType,
    baseWeight: {},
    dynamicWeight,
    dimensionSchema,
    formulaConfig: { formula },
    priority: 100,
    status: 'active',
    metadata: {},
  };
}

function isPlainObject(value: unknown) {
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}

function scalarToString(value: unknown): string {
  if (value === undefined || value === null) return '';
  if (typeof value === 'object') return JSON.stringify(value);
  return String(value);
}

function parseScalar(value: string): unknown {
  const trimmed = value.trim();
  if (trimmed === '') return '';
  if (trimmed === 'true') return true;
  if (trimmed === 'false') return false;
  if (/^-?\d+(\.\d+)?$/.test(trimmed)) return Number(trimmed);
  if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
    try { return JSON.parse(trimmed) as unknown; } catch { return value; }
  }
  return value;
}

function rowsToRecord(rows: Array<[string, unknown]>): RecordValue {
  return Object.fromEntries(rows.filter(([key]) => key.trim()).map(([key, value]) => [key.trim(), value]));
}

function nextKey(value: RecordValue, prefix: string) {
  let index = 1;
  while (`${prefix}${index}` in value) index += 1;
  return `${prefix}${index}`;
}
