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

import { applyEllipsisToLastLine } from './ellipsis';
import type { ApplyOverflowFallbackInput, ApplyOverflowFallbackResult, PartialLayoutInput, PartialLayoutLine } from './types';

function nTokens(tokens: Token[]): number {
  return Array.isArray(tokens) ? tokens.length : 0;
}

function coversToEnd(partial: PartialLayoutInput | null | undefined, n: number): boolean {
  if (!partial || !Array.isArray(partial.lines) || partial.lines.length === 0) return false;
  const last = partial.lines[partial.lines.length - 1];
  return (last?.end ?? -1) === n;
}

function buildLinesFromPartial(args: {
  tokens: Token[];
  partial?: PartialLayoutInput | null;
  maxLines: number;
  lang: 'TC' | 'EN';
}): Array<{ start: number; end: number; text: string }> {
  const N = nTokens(args.tokens);
  const maxLines = Math.max(1, args.maxLines | 0);
  const rawSeparators = args.lang === 'TC' ? Array.from({ length: Math.max(0, N) }, () => '') : undefined;

  if (args.partial && Array.isArray(args.partial.lines) && args.partial.lines.length > 0) {
    const out: Array<{ start: number; end: number; text: string }> = [];
    for (const line of args.partial.lines.slice(0, maxLines)) {
      const start = Math.max(0, line.start | 0);
      const end = Math.min(N, Math.max(start, line.end | 0));
      const text = line.text ?? joinTokens(args.tokens, start, end, rawSeparators);
      out.push({ start, end, text });
    }
    return out;
  }

  // 若没有 partial：把全文当单行 best-effort
  return [{ start: 0, end: N, text: joinTokens(args.tokens, 0, N, rawSeparators) }];
}

function toWrapped(lines: string[]): { lines: string[]; wrappedText: string } {
  const outLines = lines.filter((s) => s !== undefined) as string[];
  return { lines: outLines, wrappedText: outLines.join('\n') };
}

function toSingleLine(tokens: Token[]): { lines: string[]; wrappedText: string } {
  const N = nTokens(tokens);
  // 注意：这里不知道语言口径，因此 SYSTEM_DEFAULT 的单行文本在上层保证传入“原文”更稳妥。
  // 为保持最小可用，这里仍使用默认 joinTokens（EN=空格 join，TC=grapheme 之间可能会有空格）。
  const text = joinTokens(tokens, 0, N);
  return { lines: [text], wrappedText: text };
}

export async function applyOverflowFallback(input: ApplyOverflowFallbackInput): Promise<ApplyOverflowFallbackResult> {
  const tokens = input.tokens ?? [];
  const N = nTokens(tokens);
  const maxLines = Math.max(1, input.maxLines | 0);

  const isOverflow = !coversToEnd(input.partialLayout, N);

  // 若其实没有 overflow：直接返回（NONE）
  if (!isOverflow) {
    const base = buildLinesFromPartial({ tokens, partial: input.partialLayout, maxLines, lang: input.lang });
    const { lines, wrappedText } = toWrapped(base.map((l) => l.text));
    return { lines, wrappedText, meta: { fallback_type: 'NONE', overflow_type: 'NONE', reason: input.reason } };
  }

  if (input.overflowMode === 'SYSTEM_DEFAULT') {
    const { lines, wrappedText } = toSingleLine(tokens);
    return { lines, wrappedText, meta: { fallback_type: 'SYSTEM_DEFAULT', overflow_type: 'NONE', reason: input.reason } };
  }

  if (input.overflowMode === 'CLIP') {
    const base = buildLinesFromPartial({ tokens, partial: input.partialLayout, maxLines, lang: input.lang });
    const { lines, wrappedText } = toWrapped(base.slice(0, maxLines).map((l) => l.text));
    return { lines, wrappedText, meta: { fallback_type: 'NONE', overflow_type: 'CLIP', reason: input.reason } };
  }

  // ELLIPSIS
  const base = buildLinesFromPartial({ tokens, partial: input.partialLayout, maxLines, lang: input.lang });
  const { lines } = await applyEllipsisToLastLine({ input, baseLines: base.slice(0, maxLines) });
  const wrapped = toWrapped(lines);
  return { ...wrapped, meta: { fallback_type: 'NONE', overflow_type: 'ELLIPSIS', reason: input.reason } };
}

