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 × 输出扣费单价。',
    match: (rule) => rule.resourceType.startsWith('text_'),
    templates: (currency) => [createTextRule(currency, 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 * ceil(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.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 size="sm" min="0" step="0.0001" type="number" value={rule.basePrice} onChange={(event) => patch({ basePrice: Number(event.target.value) })} />
        </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, 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,
        outputTokenPrice,
      },
      dimensionSchema: {
        ...(props.rule.dimensionSchema ?? {}),
        metrics: ['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="输入单价/1K tokens">
          <Input size="sm" min="0" step="0.0001" type="number" value={prices.inputTokenPrice} onChange={(event) => updatePrices(Number(event.target.value), prices.outputTokenPrice)} />
        </PricingFormRow>
        <PricingFormRow label="输出单价/1K tokens">
          <Input size="sm" min="0" step="0.0001" type="number" value={prices.outputTokenPrice} onChange={(event) => updatePrices(prices.inputTokenPrice, 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');
  const inputRule = rules.find((rule) => rule.resourceType === 'text_input');
  const outputRule = rules.find((rule) => rule.resourceType === 'text_output');
  const source = totalRule ?? inputRule ?? outputRule ?? createTextRule(currency, 0.01, 0.03);
  return createTextRule(
    source.currency ?? currency,
    Number(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 = 'input_tokens / 1000 * input_token_price + output_tokens / 1000 * output_token_price';

function createTextRule(currency: string, inputTokenPrice: 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', 'output_tokens'],
      unitScale: 1000,
      ...(source?.dimensionSchema ?? {}),
    },
    formulaConfig: {
      ...(source?.formulaConfig ?? {}),
      formula: textFormula,
      inputTokenPrice,
      outputTokenPrice,
    },
    priority: source?.priority ?? 100,
    status: source?.status ?? 'active',
    metadata: source?.metadata ?? {},
  };
}

function textPrices(rule: PricingRuleInput) {
  return {
    inputTokenPrice: Number(rule.formulaConfig?.inputTokenPrice ?? rule.basePrice ?? 0.01),
    outputTokenPrice: Number(rule.formulaConfig?.outputTokenPrice ?? 0.03),
  };
}

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}`;
}
