import type { Token } from '../core/types';
import { joinTokens } from '../core/joinTokens';
import { measureWidthCached } from '../measure/measureWidthCached';

import type { ApplyOverflowFallbackInput } from './types';

const DEFAULT_TC_PUNCTS = ['，', '。', '！', '？', '；', '：', '、'];

export function cleanLineBeforeEllipsis(line: string, lang: 'TC' | 'EN', tcPunctuations?: string[]): string {
  const s = String(line ?? '');
  const trimmed = s.replace(/\s+$/g, '');
  if (trimmed === '') return '';

  if (lang === 'TC') {
    const puncts = new Set(tcPunctuations && tcPunctuations.length > 0 ? tcPunctuations : DEFAULT_TC_PUNCTS);
    const last = trimmed.slice(-1);
    if (puncts.has(last)) return trimmed.slice(0, -1);
  }

  return trimmed;
}

async function measureIfPossible(args: {
  text: string;
  input: ApplyOverflowFallbackInput;
}): Promise<number | null> {
  const { input, text } = args;
  if (!input.measure) return null;

  const enabled =
    typeof input.measure.measureWidthImpl === 'function' &&
    (input.measure.context === 'APP' || input.measure.widgetEnableMeasure === true);

  if (!enabled) return null;

  const res = await measureWidthCached({
    text,
    context: input.measure.context,
    contextProfile: input.measure.contextProfile,
    fontSpec: input.measure.fontSpec,
    measureWidthImpl: input.measure.measureWidthImpl,
    widgetEnableMeasure: input.measure.widgetEnableMeasure,
  });

  return res.width;
}

/**
 * 给最后一行加省略号，并在可测量时保证不超宽：
 * - EN 回退单位：整词（token）
 * - TC 回退单位：grapheme（token）
 */
export async function applyEllipsisToLastLine(args: {
  input: ApplyOverflowFallbackInput;
  baseLines: Array<{ start: number; end: number; text: string }>;
}): Promise<{ lines: string[] }> {
  const { input } = args;
  const maxLines = Math.max(1, input.maxLines | 0);
  const lines = args.baseLines.slice(0, maxLines);
  if (lines.length === 0) return { lines: [] };

  const lastIdx = lines.length - 1;
  const last = lines[lastIdx]!;

  // 先按规则清理，再拼接 ellipsisToken
  const cleaned = cleanLineBeforeEllipsis(last.text, input.lang, input.tcPunctuations);
  let candidateText = `${cleaned}${input.ellipsisToken}`;

  // 若无测量能力：直接输出（确定性）
  const measured = await measureIfPossible({ text: candidateText, input });
  if (measured === null) {
    const out = lines.map((l, idx) => (idx === lastIdx ? candidateText : l.text));
    return { lines: out };
  }

  // 有测量能力：若超宽则按 token 回退
  if (measured <= input.availableWidth) {
    const out = lines.map((l, idx) => (idx === lastIdx ? candidateText : l.text));
    return { lines: out };
  }

  // 回退：逐步减少最后一行 token 数再加省略号
  let end = last.end;
  const start = last.start;
  let foundFit = false;
  while (end > start) {
    end -= 1;
    const base = joinTokens(input.tokens, start, end);
    const cleaned2 = cleanLineBeforeEllipsis(base, input.lang, input.tcPunctuations);
    const nextCandidate = `${cleaned2}${input.ellipsisToken}`;
    const w = await measureIfPossible({ text: nextCandidate, input });
    if (w !== null && w <= input.availableWidth) {
      candidateText = nextCandidate;
      foundFit = true;
      break;
    }
  }

  // 若连“仅省略号”都无法满足宽度（极窄场景），也必须给出确定性输出：直接输出 ellipsisToken
  // 注意：这可能仍然超宽，但已是最小可表达形式；上层可通过 meta 做治理。
  if (!foundFit) {
    candidateText = input.ellipsisToken;
  }

  const out = lines.map((l, idx) => (idx === lastIdx ? candidateText : l.text));
  return { lines: out };
}

