import { PDFDocument } from "pdf-lib";
import type { ToolInput } from "../../core/io/input-types";
import type { ToolResult } from "../../core/io/output-types";
import type { ToolContext } from "../../core/plugins/plugin-types";
import type { PdfSplitterOptions } from "./index";

export function parsePageRange(rangeStr: string, maxPages: number): number[] {
  const indices: number[] = [];
  const parts = rangeStr.replace(/\s+/g, "").split(",");

  for (const part of parts) {
    if (!part) continue;

    if (part.includes("-")) {
      const bounds = part.split("-");
      if (bounds.length === 2) {
        const start = parseInt(bounds[0], 10);
        const end = parseInt(bounds[1], 10);

        if (!isNaN(start) && !isNaN(end)) {
          const step = start <= end ? 1 : -1;
          for (let i = start; start <= end ? i <= end : i >= end; i += step) {
            // Convert to 0-based index
            const idx = i - 1;
            if (idx >= 0 && idx < maxPages) {
              indices.push(idx);
            }
          }
        }
      }
    } else {
      const page = parseInt(part, 10);
      if (!isNaN(page)) {
        const idx = page - 1;
        if (idx >= 0 && idx < maxPages) {
          indices.push(idx);
        }
      }
    }
  }

  return indices;
}

export async function runPdfSplitter(
  input: ToolInput,
  options: PdfSplitterOptions,
  context: ToolContext
): Promise<ToolResult> {
  const files = input.files;
  if (!files || !Array.isArray(files) || files.length === 0) {
    throw new Error("No PDF file uploaded.");
  }

  const file = files[0];
  const fileBuffer = await file.arrayBuffer();

  try {
    context.reportProgress({ percentage: 10, message: "Loading PDF document..." });
    const srcDoc = await PDFDocument.load(new Uint8Array(fileBuffer));
    const totalPages = srcDoc.getPageCount();

    const baseName = file.name.endsWith(".pdf")
      ? file.name.substring(0, file.name.length - 4)
      : file.name;

    if (options.splitMode === "burst") {
      const outFiles = [];
      for (let i = 0; i < totalPages; i++) {
        if (context.signal?.aborted) {
          throw new DOMException("Operation cancelled", "AbortError");
        }

        context.reportProgress({
          percentage: 10 + (i / totalPages) * 80,
          message: `Splitting page ${i + 1} of ${totalPages}...`,
        });

        const newDoc = await PDFDocument.create();
        const [copiedPage] = await newDoc.copyPages(srcDoc, [i]);
        newDoc.addPage(copiedPage);

        const bytes = await newDoc.save();
        const blob = new Blob([bytes as unknown as BlobPart], { type: "application/pdf" });

        outFiles.push({
          name: `${baseName}_page_${i + 1}.pdf`,
          mimeType: "application/pdf",
          blob: blob,
          sizeAfter: blob.size,
        });
      }

      context.reportProgress({ percentage: 100, message: "Done!" });
      return {
        type: "files",
        files: outFiles,
      };
    } else {
      // Extract Range mode
      context.reportProgress({ percentage: 30, message: "Parsing page range..." });
      const targetIndices = parsePageRange(options.pageRange || "1", totalPages);

      if (targetIndices.length === 0) {
        throw new Error(`No valid pages selected. The PDF only has ${totalPages} page(s).`);
      }

      context.reportProgress({ percentage: 50, message: "Copying requested pages..." });
      const newDoc = await PDFDocument.create();
      const copiedPages = await newDoc.copyPages(srcDoc, targetIndices);
      copiedPages.forEach((page) => newDoc.addPage(page));

      context.reportProgress({ percentage: 80, message: "Saving new PDF..." });
      const bytes = await newDoc.save();
      const blob = new Blob([bytes as unknown as BlobPart], { type: "application/pdf" });

      context.reportProgress({ percentage: 100, message: "Done!" });
      return {
        type: "files",
        files: [
          {
            name: `${baseName}_extracted.pdf`,
            mimeType: "application/pdf",
            blob: blob,
            sizeAfter: blob.size,
          },
        ],
      };
    }
  } catch (error) {
    console.error("PDF Split Error:", error);
    throw error instanceof Error ? error : new Error("Unknown error occurred during PDF splitting");
  }
}
