import type { ParsedBlock } from "../client/parsers/contracts.ts";
import {
  contentFingerprint,
  detectPrimaryLanguage,
  splitReadableSegments,
} from "./text.ts";

export interface EditableChapter {
  id: string;
  title: string;
  position: number;
  pageStart?: number;
  pageEnd?: number;
  blocks: ParsedBlock[];
  sourceKind?: "epub" | "pdf_text" | "ocr" | "manual";
}

export interface ChapterSegment {
  id: string;
  sourceBlockId: string;
  position: number;
  text: string;
  language: "zh-CN" | "en-US";
  contentHash: string;
  pageNumber?: number;
  included: boolean;
  sourceKind: "epub" | "pdf_text" | "ocr" | "manual";
  ocrConfidence: number | null;
  warning: string | null;
}

export async function buildChapterSegments(
  chapter: EditableChapter,
): Promise<ChapterSegment[]> {
  const segments: ChapterSegment[] = [];
  for (const block of chapter.blocks) {
    const blockSegments = block.included
      ? splitReadableSegments(block.text)
      : [{ text: block.text, language: detectPrimaryLanguage(block.text) }];
    for (let sentenceIndex = 0; sentenceIndex < blockSegments.length; sentenceIndex += 1) {
      const readable = blockSegments[sentenceIndex];
      const contentHash = await contentFingerprint(readable.text);
      const identityHash = await contentFingerprint(
        `${chapter.id}\n${block.id}\n${sentenceIndex}`,
      );
      segments.push({
        id: `seg-${identityHash.slice(0, 24)}`,
        sourceBlockId: block.id,
        position: segments.length,
        text: readable.text,
        language: readable.language,
        contentHash,
        pageNumber: block.pageNumber,
        included: block.included,
        sourceKind: chapter.sourceKind ?? "manual",
        ocrConfidence: block.confidence ?? null,
        warning:
          block.warning ??
          (block.kind === "formula" || block.kind === "table" ? block.kind : null),
      });
    }
  }
  return segments;
}

function pageRange(blocks: readonly ParsedBlock[]) {
  const pages = blocks
    .map((block) => block.pageNumber)
    .filter((value): value is number => typeof value === "number");
  return pages.length
    ? { pageStart: Math.min(...pages), pageEnd: Math.max(...pages) }
    : {};
}

export function splitChapter(
  chapter: EditableChapter,
  firstBlockIdOfRight: string,
  rightTitle: string,
): [EditableChapter, EditableChapter] {
  const index = chapter.blocks.findIndex((block) => block.id === firstBlockIdOfRight);
  if (index === 0) throw new Error("不能在第一段之前拆分章节。");
  if (index < 0) throw new Error("找不到拆分位置。");
  const title = rightTitle.trim();
  if (!title) throw new Error("新章节标题不能为空。");
  const leftBlocks = chapter.blocks.slice(0, index);
  const rightBlocks = chapter.blocks.slice(index);
  return [
    { ...chapter, blocks: leftBlocks, ...pageRange(leftBlocks) },
    {
      ...chapter,
      id: crypto.randomUUID(),
      title,
      position: chapter.position + 1,
      blocks: rightBlocks,
      ...pageRange(rightBlocks),
    },
  ];
}

export function mergeAdjacentChapters(
  left: EditableChapter,
  right: EditableChapter,
  title: string,
): EditableChapter {
  if (right.position !== left.position + 1) {
    throw new Error("只能合并相邻章节。");
  }
  const mergedTitle = title.trim();
  if (!mergedTitle) throw new Error("章节标题不能为空。");
  const blocks = [...left.blocks, ...right.blocks];
  const inferredRange = pageRange(blocks);
  const pageStart = Math.min(
    left.pageStart ?? inferredRange.pageStart ?? Number.POSITIVE_INFINITY,
    right.pageStart ?? inferredRange.pageStart ?? Number.POSITIVE_INFINITY,
  );
  const pageEnd = Math.max(
    left.pageEnd ?? inferredRange.pageEnd ?? Number.NEGATIVE_INFINITY,
    right.pageEnd ?? inferredRange.pageEnd ?? Number.NEGATIVE_INFINITY,
  );
  return {
    ...left,
    title: mergedTitle,
    blocks,
    ...(Number.isFinite(pageStart) ? { pageStart } : {}),
    ...(Number.isFinite(pageEnd) ? { pageEnd } : {}),
  };
}
