import { Plus, Trash2 } from 'lucide-react';
import type { RateLimitMetric, RateLimitPolicy } from '@easyai-ai-gateway/contracts';
import { Button, Input, Select } from '../../components/ui';

export type UserGroupRateLimitRuleForm = {
  id: string;
  metric: RateLimitMetric;
  limit: string;
  windowSeconds: string;
  leaseTtlSeconds: string;
  maxWaitSeconds: string;
  consume: string;
  extra: Record<string, unknown>;
};

export type UserGroupQuotaEntryForm = {
  id: string;
  key: string;
  valueType: 'number' | 'string' | 'boolean' | 'json';
  value: string;
};

const rateLimitMetrics: Array<{ value: RateLimitMetric; label: string }> = [
  { value: 'rpm', label: 'RPM / 每分钟请求' },
  { value: 'rps', label: 'RPS / 每秒请求' },
  { value: 'tpm_total', label: 'TPM / 总 Token' },
  { value: 'tpm_input', label: '输入 TPM' },
  { value: 'tpm_output', label: '输出 TPM' },
  { value: 'concurrent', label: '并发请求' },
  { value: 'queue_size', label: '排队数量' },
];

let policyEditorRowSequence = 0;

export function UserGroupRateLimitEditor(props: {
  value: UserGroupRateLimitRuleForm[];
  onChange: (value: UserGroupRateLimitRuleForm[]) => void;
}) {
  function update(id: string, patch: Partial<UserGroupRateLimitRuleForm>) {
    props.onChange(props.value.map((item) => item.id === id ? { ...item, ...patch } : item));
  }

  return (
    <section className="userGroupPolicyEditor spanTwo">
      <header className="userGroupPolicyHeader">
        <div>
          <strong>限流策略</strong>
          <span>按指标设置独立上限；留空表示不配置该规则。</span>
        </div>
        <Button type="button" size="xs" variant="outline" onClick={() => props.onChange([
          ...props.value,
          createRateLimitRuleForm(nextAvailableMetric(props.value)),
        ])}>
          <Plus size={13} />添加规则
        </Button>
      </header>
      <div className="userGroupPolicyTable userGroupRateLimitTable" role="table" aria-label="用户组限流策略">
        <div className="userGroupPolicyRow userGroupPolicyTableHead" role="row">
          <span role="columnheader">指标</span>
          <span role="columnheader">上限</span>
          <span role="columnheader">窗口（秒）</span>
          <span role="columnheader">租约 TTL（秒）</span>
          <span role="columnheader">最长等待（秒）</span>
          <span role="columnheader">消费方式</span>
          <span role="columnheader">操作</span>
        </div>
        {props.value.map((rule) => (
          <div className="userGroupPolicyRow" role="row" key={rule.id}>
            <Select
              aria-label="限流指标"
              size="sm"
              value={rule.metric}
              onChange={(event) => {
                const metric = event.target.value as RateLimitMetric;
                update(rule.id, {
                  metric,
                  windowSeconds: metric === 'queue_size' || metric === 'concurrent' ? '' : (rule.windowSeconds || '60'),
                  leaseTtlSeconds: metric === 'concurrent' ? (rule.leaseTtlSeconds || '120') : '',
                  maxWaitSeconds: metric === 'queue_size' ? (rule.maxWaitSeconds || '600') : '',
                  consume: metric === 'queue_size' ? '' : rule.consume,
                });
              }}
            >
              {rateLimitMetrics.map((item) => <option value={item.value} key={item.value}>{item.label}</option>)}
            </Select>
            <Input aria-label={`${metricLabel(rule.metric)}上限`} size="sm" inputMode="decimal" value={rule.limit} placeholder="不限" onChange={(event) => update(rule.id, { limit: event.target.value })} />
            <Input aria-label={`${metricLabel(rule.metric)}窗口秒数`} size="sm" inputMode="numeric" value={rule.windowSeconds} placeholder={rule.metric === 'queue_size' || rule.metric === 'concurrent' ? '-' : '60'} disabled={rule.metric === 'queue_size' || rule.metric === 'concurrent'} onChange={(event) => update(rule.id, { windowSeconds: event.target.value })} />
            <Input aria-label={`${metricLabel(rule.metric)}租约 TTL`} size="sm" inputMode="numeric" value={rule.leaseTtlSeconds} placeholder={rule.metric === 'concurrent' ? '120' : '-'} disabled={rule.metric !== 'concurrent'} onChange={(event) => update(rule.id, { leaseTtlSeconds: event.target.value })} />
            <Input aria-label={`${metricLabel(rule.metric)}最长等待`} size="sm" inputMode="numeric" value={rule.maxWaitSeconds} placeholder={rule.metric === 'queue_size' ? '600' : '-'} disabled={rule.metric !== 'queue_size'} onChange={(event) => update(rule.id, { maxWaitSeconds: event.target.value })} />
            <Select aria-label={`${metricLabel(rule.metric)}消费方式`} size="sm" value={rule.consume} disabled={rule.metric === 'queue_size'} onChange={(event) => update(rule.id, { consume: event.target.value })}>
              <option value="">默认</option>
              <option value="fixed_window">固定窗口</option>
              <option value="reserve_then_reconcile">预占后核销</option>
              {rule.consume && !['fixed_window', 'reserve_then_reconcile'].includes(rule.consume) && <option value={rule.consume}>{rule.consume}</option>}
            </Select>
            <Button type="button" aria-label={`删除${metricLabel(rule.metric)}规则`} size="xs" variant="ghost" onClick={() => props.onChange(props.value.filter((item) => item.id !== rule.id))}>
              <Trash2 size={13} />
            </Button>
          </div>
        ))}
        {!props.value.length && <div className="userGroupPolicyEmpty">未配置限流规则，当前用户组不追加组级限流。</div>}
      </div>
    </section>
  );
}

export function UserGroupQuotaPolicyEditor(props: {
  value: UserGroupQuotaEntryForm[];
  onChange: (value: UserGroupQuotaEntryForm[]) => void;
}) {
  function update(id: string, patch: Partial<UserGroupQuotaEntryForm>) {
    props.onChange(props.value.map((item) => item.id === id ? { ...item, ...patch } : item));
  }

  return (
    <section className="userGroupPolicyEditor spanTwo">
      <header className="userGroupPolicyHeader">
        <div>
          <strong>额度策略</strong>
          <span>额度字段保持开放，可维护数字、文本、布尔值或 JSON。</span>
        </div>
        <Button type="button" size="xs" variant="outline" onClick={() => props.onChange([
          ...props.value,
          createQuotaEntryForm(),
        ])}>
          <Plus size={13} />添加额度
        </Button>
      </header>
      <div className="userGroupPolicyTable userGroupQuotaTable" role="table" aria-label="用户组额度策略">
        <div className="userGroupPolicyRow userGroupPolicyTableHead" role="row">
          <span role="columnheader">字段</span>
          <span role="columnheader">值类型</span>
          <span role="columnheader">值</span>
          <span role="columnheader">操作</span>
        </div>
        {props.value.map((entry) => (
          <div className="userGroupPolicyRow" role="row" key={entry.id}>
            <Input aria-label="额度字段" size="sm" value={entry.key} placeholder="例如 monthlyResource" onChange={(event) => update(entry.id, { key: event.target.value })} />
            <Select
              aria-label={`${entry.key || '额度'}值类型`}
              size="sm"
              value={entry.valueType}
              onChange={(event) => {
                const valueType = event.target.value as UserGroupQuotaEntryForm['valueType'];
                update(entry.id, { valueType, value: quotaValueForType(valueType, entry.value) });
              }}
            >
              <option value="number">数字</option>
              <option value="string">文本</option>
              <option value="boolean">布尔值</option>
              <option value="json">JSON</option>
            </Select>
            {entry.valueType === 'boolean' ? (
              <Select aria-label={`${entry.key || '额度'}值`} size="sm" value={entry.value} onChange={(event) => update(entry.id, { value: event.target.value })}>
                <option value="true">true</option>
                <option value="false">false</option>
              </Select>
            ) : (
              <Input
                aria-label={`${entry.key || '额度'}值`}
                size="sm"
                inputMode={entry.valueType === 'number' ? 'decimal' : undefined}
                value={entry.value}
                placeholder={entry.valueType === 'json' ? '{"key":"value"}' : '请输入值'}
                onChange={(event) => update(entry.id, { value: event.target.value })}
              />
            )}
            <Button type="button" aria-label={`删除额度字段 ${entry.key || '未命名'}`} size="xs" variant="ghost" onClick={() => props.onChange(props.value.filter((item) => item.id !== entry.id))}>
              <Trash2 size={13} />
            </Button>
          </div>
        ))}
        {!props.value.length && <div className="userGroupPolicyEmpty">未配置额度策略。</div>}
      </div>
    </section>
  );
}

export function rateLimitPolicyToForm(policy?: RateLimitPolicy) {
  const rules = Array.isArray(policy?.rules) ? policy.rules : [];
  const extra = { ...(policy ?? {}) };
  delete extra.rules;
  return {
    extra,
    rules: rules.map((rule) => {
      const raw = rule as unknown as Record<string, unknown>;
      const ruleExtra = { ...raw };
      delete ruleExtra.metric;
      delete ruleExtra.limit;
      delete ruleExtra.windowSeconds;
      delete ruleExtra.leaseTtlSeconds;
      delete ruleExtra.maxWaitSeconds;
      delete ruleExtra.consume;
      return {
        id: nextPolicyEditorRowId('rate'),
        metric: normalizeMetric(rule.metric),
        limit: numberText(rule.limit),
        windowSeconds: numberText(rule.windowSeconds),
        leaseTtlSeconds: numberText(rule.leaseTtlSeconds),
        maxWaitSeconds: rule.metric === 'queue_size' ? numberText(rule.maxWaitSeconds) || '600' : '',
        consume: typeof rule.consume === 'string' ? rule.consume : '',
        extra: ruleExtra,
      };
    }),
  };
}

export function rateLimitPolicyFromForm(
  rules: UserGroupRateLimitRuleForm[],
  extra: Record<string, unknown>,
): RateLimitPolicy | undefined {
  const metrics = new Set<string>();
  const normalizedRules = rules.flatMap((rule) => {
    if (!rule.limit.trim()) return [];
    if (rule.metric === 'queue_size' && Number(rule.limit) === 0) return [];
    if (metrics.has(rule.metric)) throw new Error(`限流指标 ${metricLabel(rule.metric)} 不能重复`);
    metrics.add(rule.metric);
    const limit = rule.metric === 'queue_size'
      ? boundedPositiveInteger(rule.limit, `${metricLabel(rule.metric)}上限`, 10000)
      : positiveNumber(rule.limit, `${metricLabel(rule.metric)}上限`);
    const windowSeconds = rule.metric === 'queue_size' ? undefined : optionalPositiveInteger(rule.windowSeconds, `${metricLabel(rule.metric)}窗口`);
    const leaseTtlSeconds = rule.metric === 'queue_size' ? undefined : optionalPositiveInteger(rule.leaseTtlSeconds, `${metricLabel(rule.metric)}租约 TTL`);
    const maxWaitSeconds = rule.metric === 'queue_size'
      ? boundedPositiveInteger(rule.maxWaitSeconds || '600', `${metricLabel(rule.metric)}最长等待`, 3600)
      : undefined;
    return [{
      ...rule.extra,
      metric: rule.metric,
      limit,
      ...(windowSeconds ? { windowSeconds } : {}),
      ...(leaseTtlSeconds ? { leaseTtlSeconds } : {}),
      ...(maxWaitSeconds ? { maxWaitSeconds } : {}),
      ...(rule.consume ? { consume: rule.consume } : {}),
    }];
  });
  const policy = {
    ...extra,
    ...(normalizedRules.length ? { rules: normalizedRules } : {}),
  };
  return Object.keys(policy).length ? policy : undefined;
}

export function quotaPolicyToForm(policy?: Record<string, unknown>) {
  return Object.entries(policy ?? {}).map(([key, value]) => {
    const serialized = serializeQuotaValue(value);
    return {
      id: nextPolicyEditorRowId('quota'),
      key,
      valueType: serialized.valueType,
      value: serialized.value,
    };
  });
}

export function quotaPolicyFromForm(entries: UserGroupQuotaEntryForm[]) {
  const policy: Record<string, unknown> = {};
  entries.forEach((entry) => {
    const key = entry.key.trim();
    if (!key && !entry.value.trim()) return;
    if (!key) throw new Error('额度字段不能为空');
    if (Object.prototype.hasOwnProperty.call(policy, key)) throw new Error(`额度字段 ${key} 不能重复`);
    policy[key] = parseQuotaValue(entry);
  });
  return Object.keys(policy).length ? policy : undefined;
}

export function rateLimitPolicySummary(policy?: RateLimitPolicy) {
  const rules = Array.isArray(policy?.rules) ? policy.rules : [];
  const parts = rules
    .filter((rule) => Number.isFinite(Number(rule.limit)) && Number(rule.limit) > 0)
    .map((rule) => rule.metric === 'queue_size'
      ? `${metricShortLabel(rule.metric)} ${compactNumber(Number(rule.limit))} / ${Number(rule.maxWaitSeconds) || 600}秒`
      : `${metricShortLabel(rule.metric)} ${compactNumber(Number(rule.limit))}`);
  if (parts.length) return parts;
  return Object.entries(policy ?? {})
    .filter(([key]) => key !== 'rules')
    .slice(0, 3)
    .map(([key, value]) => `${key} ${compactValue(value)}`);
}

export function quotaPolicySummary(policy?: Record<string, unknown>) {
  return Object.entries(policy ?? {}).slice(0, 3).map(([key, value]) => `${key} ${compactValue(value)}`);
}

function createRateLimitRuleForm(metric: RateLimitMetric): UserGroupRateLimitRuleForm {
  return {
    id: nextPolicyEditorRowId('rate'),
    metric,
    limit: '',
    windowSeconds: metric === 'concurrent' ? '' : '60',
    leaseTtlSeconds: metric === 'concurrent' ? '120' : '',
    maxWaitSeconds: metric === 'queue_size' ? '600' : '',
    consume: '',
    extra: {},
  };
}

function createQuotaEntryForm(): UserGroupQuotaEntryForm {
  return {
    id: nextPolicyEditorRowId('quota'),
    key: '',
    valueType: 'number',
    value: '',
  };
}

function nextAvailableMetric(rules: UserGroupRateLimitRuleForm[]) {
  return rateLimitMetrics.find((item) => !rules.some((rule) => rule.metric === item.value))?.value ?? 'rpm';
}

function nextPolicyEditorRowId(prefix: string) {
  policyEditorRowSequence += 1;
  return `${prefix}-${policyEditorRowSequence}`;
}

function normalizeMetric(value: string): RateLimitMetric {
  return rateLimitMetrics.some((item) => item.value === value) ? value as RateLimitMetric : 'rpm';
}

function metricLabel(metric: string) {
  return rateLimitMetrics.find((item) => item.value === metric)?.label ?? metric;
}

function metricShortLabel(metric: string) {
  return ({
    rpm: 'RPM',
    rps: 'RPS',
    tpm_total: 'TPM',
    tpm_input: '输入 TPM',
    tpm_output: '输出 TPM',
    concurrent: '并发',
    queue_size: '排队',
  } as Record<string, string>)[metric] ?? metric;
}

function numberText(value: unknown) {
  return typeof value === 'number' && Number.isFinite(value) ? String(value) : '';
}

function positiveNumber(value: string, label: string) {
  const parsed = Number(value);
  if (!Number.isFinite(parsed) || parsed <= 0) throw new Error(`${label}必须是大于 0 的数字`);
  return parsed;
}

function optionalPositiveInteger(value: string, label: string) {
  if (!value.trim()) return undefined;
  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`${label}必须是大于 0 的整数`);
  return parsed;
}

function boundedPositiveInteger(value: string, label: string, max: number) {
  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed < 1 || parsed > max) {
    throw new Error(`${label}必须是 1–${max} 的整数`);
  }
  return parsed;
}

function serializeQuotaValue(value: unknown): Pick<UserGroupQuotaEntryForm, 'valueType' | 'value'> {
  if (typeof value === 'number') return { valueType: 'number', value: String(value) };
  if (typeof value === 'boolean') return { valueType: 'boolean', value: String(value) };
  if (typeof value === 'string') return { valueType: 'string', value };
  return { valueType: 'json', value: JSON.stringify(value) ?? 'null' };
}

function parseQuotaValue(entry: UserGroupQuotaEntryForm) {
  if (entry.valueType === 'string') return entry.value;
  if (entry.valueType === 'boolean') return entry.value === 'true';
  if (entry.valueType === 'number') {
    const value = Number(entry.value);
    if (!Number.isFinite(value) || value < 0) throw new Error(`额度字段 ${entry.key} 必须是大于或等于 0 的数字`);
    return value;
  }
  try {
    return JSON.parse(entry.value) as unknown;
  } catch {
    throw new Error(`额度字段 ${entry.key} 必须是有效 JSON`);
  }
}

function quotaValueForType(valueType: UserGroupQuotaEntryForm['valueType'], current: string) {
  if (valueType === 'boolean') return current === 'false' ? 'false' : 'true';
  if (valueType === 'number') return Number.isFinite(Number(current)) ? current : '';
  if (valueType === 'json') {
    try {
      JSON.parse(current);
      return current;
    } catch {
      return '{}';
    }
  }
  return current;
}

function compactNumber(value: number) {
  return new Intl.NumberFormat('zh-CN', { notation: 'compact', maximumFractionDigits: 1 }).format(value);
}

function compactValue(value: unknown) {
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value);
  const text = JSON.stringify(value) ?? String(value);
  return text.length > 18 ? `${text.slice(0, 17)}…` : text;
}
