import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import path from 'path';
import os from 'os';
import type { ChapterFile, ChapterView, TextFragment } from '../types.ts';

const TOC_FILENAME = 'toc.links';

function looksLikeFragments(content: string): boolean {
  try {
    const parsed = JSON.parse(content);
    return (
      Array.isArray(parsed) &&
      parsed.length > 0 &&
      typeof parsed[0] === 'object' &&
      parsed[0] !== null &&
      'body' in (parsed[0] as object)
    );
  } catch {
    return false;
  }
}

export class Cache {
  private readonly base: string;

  constructor(basePath: string) {
    this.base = basePath.replace(/^~/, os.homedir());
  }

  private chapterPath(id: number, index: number): string {
    return path.join(this.base, String(id), String(index));
  }

  private tocPath(id: number): string {
    return path.join(this.base, String(id), TOC_FILENAME);
  }

  private ensureDir(id: number): void {
    const dir = path.join(this.base, String(id));
    if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
  }

  tryGetChapters(id: number, from: number, to: number): ChapterView | null {
    if (from > to) return null;

    const chapters: ChapterFile[] = [];
    for (let i = from; i <= to; i++) {
      const p = this.chapterPath(id, i);
      if (!existsSync(p)) return null;
      const content = readFileSync(p, 'utf-8');
      if (content.length < 10) return null;
      chapters.push({ path: p, hasStyle: looksLikeFragments(content) });
    }
    return { id, min: from, max: to, chapters };
  }

  tryGetToc(id: number): string[] | null {
    const p = this.tocPath(id);
    if (!existsSync(p)) return null;
    const lines = readFileSync(p, 'utf-8')
      .split('\n')
      .map(l => l.trim())
      .filter(Boolean);
    if (lines.length === 0) return null;
    return lines;
  }

  saveChapters(id: number, chapters: { index: number; content: string }[]): ChapterFile[] {
    this.ensureDir(id);
    return chapters.map(({ index, content }) => {
      const p = this.chapterPath(id, index);
      writeFileSync(p, content, 'utf-8');
      return { path: p, hasStyle: looksLikeFragments(content) };
    });
  }

  saveToc(id: number, urls: string[]): void {
    this.ensureDir(id);
    writeFileSync(this.tocPath(id), urls.join('\n'), 'utf-8');
  }
}
