import { promises as fs } from 'node:fs';
import { join, dirname } from 'node:path';

/**
 * 小说拆解工具类
 */
export class NovelSplitter {
  /**
   * 章节标记正则表达式，适配常见小说格式
   */
  private static readonly CHAPTER_PATTERNS = [
    // 第1章 标题
    /^\s*第\s*([零一二三四五六七八九十百千万]+|\d+)\s*章\s*[：:]*\s*([^\n]+)?\s*$/,
    // 第一章 标题
    /^\s*第\s*[零一二三四五六七八九十百千万]+\s*章\s*[：:]*\s*([^\n]+)?\s*$/,
    // Chapter 1: 标题
    /^\s*Chapter\s*\d+\s*[：:]*\s*([^\n]+)?\s*$/i,
    // 卷一 第一章 标题
    /^\s*卷\s*([零一二三四五六七八九十百千万]+|\d+)\s*第\s*([零一二三四五六七八九十百千万]+|\d+)\s*章\s*[：:]*\s*([^\n]+)?\s*$/,
    // 第一卷 第一章 标题
    /^\s*第\s*([零一二三四五六七八九十百千万]+|\d+)\s*卷\s*第\s*([零一二三四五六七八九十百千万]+|\d+)\s*章\s*[：:]*\s*([^\n]+)?\s*$/,
    // 1. 标题
    /^\s*\d+\s*[．.]\s*([^\n]+)?\s*$/,
    // 1、标题
    /^\s*\d+\s*[、]\s*([^\n]+)?\s*$/,
  ];

  /**
   * 读取文件内容
   * @param filePath 文件路径
   * @returns 文件内容
   */
  private static async readFile(filePath: string): Promise<string> {
    return fs.readFile(filePath, 'utf-8');
  }

  /**
   * 检查并创建目录
   * @param dirPath 目录路径
   */
  private static async ensureDirectory(dirPath: string): Promise<void> {
    try {
      await fs.mkdir(dirPath, { recursive: true });
    } catch (error) {
      if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {
        throw error;
      }
    }
  }

  /**
   * 识别章节标记
   * @param line 文本行
   * @returns 是否为章节标记
   */
  private static isChapterMarker(line: string): boolean {
    return this.CHAPTER_PATTERNS.some(pattern => pattern.test(line));
  }

  /**
   * 按章节数量拆解小说
   * @param filePath 小说文件路径
   * @param outputDir 输出目录
   * @param chapterCount 章节数量，默认10章
   * @returns 拆解后的文件列表
   */
  static async splitByChapterCount(
    filePath: string,
    outputDir: string,
    chapterCount: number = 10
  ): Promise<string[]> {
    // 读取文件内容
    const content = await this.readFile(filePath);
    
    // 检查并创建输出目录
    await this.ensureDirectory(outputDir);
    
    // 按行分割文本
    const lines = content.split('\n');
    
    // 识别章节位置
    const chapters: { start: number; end: number; title: string }[] = [];
    let currentChapterStart = 0;
    let chapterTitle = '';
    
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i];
      
      if (this.isChapterMarker(line)) {
        // 如果不是第一个章节，保存上一个章节
        if (chapters.length > 0) {
          chapters[chapters.length - 1].end = i;
        }
        
        // 提取章节标题
        chapterTitle = line.trim();
        
        // 开始新章节
        chapters.push({
          start: i,
          end: lines.length,
          title: chapterTitle
        });
        
        currentChapterStart = i;
      }
    }
    
    // 确保最后一个章节有结束位置
    if (chapters.length > 0) {
      chapters[chapters.length - 1].end = lines.length;
    }
    
    // 如果没有识别到章节标记，按固定行数分割
    if (chapters.length === 0) {
      const totalLines = lines.length;
      const linesPerPart = Math.ceil(totalLines / chapterCount);
      
      for (let i = 0; i < chapterCount; i++) {
        const start = i * linesPerPart;
        const end = Math.min((i + 1) * linesPerPart, totalLines);
        
        if (start < end) {
          chapters.push({
            start,
            end,
            title: `第${i + 1}部分`
          });
        }
      }
    }
    
    // 按固定章节数拆解，每chapterCount章为一个part
    const parts: string[][] = [];
    const totalParts = Math.ceil(chapters.length / chapterCount);
    
    for (let i = 0; i < totalParts; i++) {
      const startChapter = i * chapterCount;
      const endChapter = Math.min((i + 1) * chapterCount, chapters.length);
      
      if (startChapter < endChapter) {
        const partLines: string[] = [];
        
        for (let j = startChapter; j < endChapter; j++) {
          const chapter = chapters[j];
          partLines.push(...lines.slice(chapter.start, chapter.end));
        }
        
        parts.push(partLines);
      }
    }
    
    // 输出拆解后的文件
    const outputFiles: string[] = [];
    
    for (let i = 0; i < parts.length; i++) {
      const partContent = parts[i].join('\n');
      const fileName = `part_${i + 1}.txt`;
      const outputPath = join(outputDir, fileName);
      
      await fs.writeFile(outputPath, partContent, 'utf-8');
      outputFiles.push(outputPath);
    }
    
    return outputFiles;
  }

  /**
   * 按章节标记拆解小说
   * @param filePath 小说文件路径
   * @param outputDir 输出目录
   * @returns 拆解后的文件列表
   */
  static async splitByChapters(
    filePath: string,
    outputDir: string
  ): Promise<string[]> {
    // 读取文件内容
    const content = await this.readFile(filePath);
    
    // 检查并创建输出目录
    await this.ensureDirectory(outputDir);
    
    // 按行分割文本
    const lines = content.split('\n');
    
    // 识别章节位置
    const chapters: { start: number; end: number; title: string }[] = [];
    
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i];
      
      if (this.isChapterMarker(line)) {
        // 提取章节标题
        const chapterTitle = line.trim();
        
        // 开始新章节
        chapters.push({
          start: i,
          end: lines.length,
          title: chapterTitle
        });
        
        // 标记上一个章节的结束位置
        if (chapters.length > 1) {
          chapters[chapters.length - 2].end = i;
        }
      }
    }
    
    // 确保最后一个章节有结束位置
    if (chapters.length > 0) {
      chapters[chapters.length - 1].end = lines.length;
    }
    
    // 输出拆解后的文件
    const outputFiles: string[] = [];
    
    for (let i = 0; i < chapters.length; i++) {
      const chapter = chapters[i];
      const chapterContent = lines.slice(chapter.start, chapter.end).join('\n');
      const fileName = `chapter_${i + 1}.txt`;
      const outputPath = join(outputDir, fileName);
      
      await fs.writeFile(outputPath, chapterContent, 'utf-8');
      outputFiles.push(outputPath);
    }
    
    return outputFiles;
  }
}

/**
 * 拆解小说的便捷函数
 * @param filePath 小说文件路径
 * @param outputDir 输出目录
 * @param chapterCount 章节数量，默认10章
 * @returns 拆解后的文件列表
 */
export async function splitNovel(
  filePath: string,
  outputDir: string,
  chapterCount: number = 10
): Promise<string[]> {
  return NovelSplitter.splitByChapterCount(filePath, outputDir, chapterCount);
}

/**
 * 按章节标记拆解小说的便捷函数
 * @param filePath 小说文件路径
 * @param outputDir 输出目录
 * @returns 拆解后的文件列表
 */
export async function splitNovelByChapters(
  filePath: string,
  outputDir: string
): Promise<string[]> {
  return NovelSplitter.splitByChapters(filePath, outputDir);
}
