const fs = require('fs');
const path = require('path');
const { PDFDocument, rgb, degrees, StandardFonts } = require('pdf-lib');

function parsePageRanges(rangeString, totalPages) {
  const pages = [];
  const ranges = rangeString.split(',').map(r => r.trim());

  for (const range of ranges) {
    if (range.includes('-')) {
      const [start, end] = range.split('-').map(n => parseInt(n.trim()));
      for (let i = start; i <= end && i <= totalPages; i++) {
        if (i > 0 && !pages.includes(i - 1)) {
          pages.push(i - 1);
        }
      }
    } else {
      const page = parseInt(range);
      if (page > 0 && page <= totalPages && !pages.includes(page - 1)) {
        pages.push(page - 1);
      }
    }
  }

  return pages.sort((a, b) => a - b);
}

function hexToRgb(hex) {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16) / 255,
    g: parseInt(result[2], 16) / 255,
    b: parseInt(result[3], 16) / 255
  } : { r: 0, g: 0, b: 0 };
}

async function pdfMerge(data) {
  try {
    const mergedPdf = await PDFDocument.create();

    for (const filePath of data.inputFiles) {
      const pdfBytes = fs.readFileSync(filePath);
      const pdf = await PDFDocument.load(pdfBytes);
      const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
      copiedPages.forEach(page => mergedPdf.addPage(page));
    }

    const pdfBytes = await mergedPdf.save();
    fs.writeFileSync(data.outputPath, pdfBytes);

    return { success: true, message: `Successfully merged ${data.inputFiles.length} PDFs` };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

async function pdfSplit(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes);
    const totalPages = pdf.getPageCount();

    const splits = [];

    if (data.splitMode === 'pages') {
      const ranges = data.pageRanges.split(',').map(r => r.trim());
      for (let i = 0; i < ranges.length; i++) {
        const range = ranges[i];
        const pages = [];

        if (range.includes('-')) {
          const [start, end] = range.split('-').map(n => parseInt(n.trim()));
          for (let p = start; p <= end && p <= totalPages; p++) {
            pages.push(p - 1);
          }
        } else {
          const page = parseInt(range);
          if (page > 0 && page <= totalPages) {
            pages.push(page - 1);
          }
        }

        if (pages.length > 0) {
          splits.push({ pages, name: `part_${i + 1}` });
        }
      }
    } else if (data.splitMode === 'interval') {
      const interval = data.interval;
      for (let i = 0; i < totalPages; i += interval) {
        const pages = [];
        for (let j = i; j < i + interval && j < totalPages; j++) {
          pages.push(j);
        }
        splits.push({ pages, name: `part_${Math.floor(i / interval) + 1}` });
      }
    } else if (data.splitMode === 'size') {
      const chunkSize = Math.max(1, Math.floor(totalPages / 5));
      for (let i = 0; i < totalPages; i += chunkSize) {
        const pages = [];
        for (let j = i; j < i + chunkSize && j < totalPages; j++) {
          pages.push(j);
        }
        splits.push({ pages, name: `part_${Math.floor(i / chunkSize) + 1}` });
      }
    }

    const baseName = path.basename(data.inputPath, '.pdf');
    for (const split of splits) {
      const newPdf = await PDFDocument.create();
      const copiedPages = await newPdf.copyPages(pdf, split.pages);
      copiedPages.forEach(page => newPdf.addPage(page));

      const outputPath = path.join(data.outputFolder, `${baseName}_${split.name}.pdf`);
      const newPdfBytes = await newPdf.save();
      fs.writeFileSync(outputPath, newPdfBytes);
    }

    return { success: true, message: `Successfully split PDF into ${splits.length} files` };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

async function pdfCompress(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes);

    const compressedPdfBytes = await pdf.save({
      useObjectStreams: true,
      addDefaultPage: false,
      objectsPerTick: 50
    });

    fs.writeFileSync(data.outputPath, compressedPdfBytes);

    const originalSize = fs.statSync(data.inputPath).size;
    const compressedSize = fs.statSync(data.outputPath).size;
    const savings = ((originalSize - compressedSize) / originalSize * 100).toFixed(1);

    return {
      success: true,
      message: `PDF compressed. Size reduced by ${savings}% (${(originalSize / 1024).toFixed(1)}KB → ${(compressedSize / 1024).toFixed(1)}KB)`
    };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

async function pdfRotate(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes);
    const totalPages = pdf.getPageCount();

    let pagesToRotate = [];
    if (data.pages && data.pages.trim()) {
      pagesToRotate = parsePageRanges(data.pages, totalPages);
    } else {
      pagesToRotate = Array.from({ length: totalPages }, (_, i) => i);
    }

    pagesToRotate.forEach(pageIndex => {
      const page = pdf.getPage(pageIndex);
      page.setRotation(degrees(data.angle));
    });

    const rotatedPdfBytes = await pdf.save();
    fs.writeFileSync(data.outputPath, rotatedPdfBytes);

    return {
      success: true,
      message: `Successfully rotated ${pagesToRotate.length} page(s) by ${data.angle}\u00B0`
    };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

async function pdfDeletePages(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes);
    const totalPages = pdf.getPageCount();

    const pagesToDelete = parsePageRanges(data.pages, totalPages);

    pagesToDelete.sort((a, b) => b - a).forEach(pageIndex => {
      pdf.removePage(pageIndex);
    });

    const newPdfBytes = await pdf.save();
    fs.writeFileSync(data.outputPath, newPdfBytes);

    return {
      success: true,
      message: `Successfully deleted ${pagesToDelete.length} page(s). New PDF has ${totalPages - pagesToDelete.length} pages`
    };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

async function pdfReorder(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes);
    const totalPages = pdf.getPageCount();

    const newOrder = data.newOrder.split(',').map(n => parseInt(n.trim()) - 1);

    if (newOrder.length !== totalPages) {
      return { success: false, error: `New order must include all ${totalPages} pages` };
    }

    const newPdf = await PDFDocument.create();
    const copiedPages = await newPdf.copyPages(pdf, newOrder);
    copiedPages.forEach(page => newPdf.addPage(page));

    const reorderedPdfBytes = await newPdf.save();
    fs.writeFileSync(data.outputPath, reorderedPdfBytes);

    return { success: true, message: 'Successfully reordered PDF pages' };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

async function pdfWatermark(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes);
    const totalPages = pdf.getPageCount();

    let pagesToWatermark = [];
    if (data.pages === 'all') {
      pagesToWatermark = Array.from({ length: totalPages }, (_, i) => i);
    } else if (data.pages === 'custom' && data.customPages) {
      pagesToWatermark = parsePageRanges(data.customPages, totalPages);
    }

    const font = await pdf.embedFont(StandardFonts.Helvetica);
    const color = hexToRgb(data.color);

    for (const pageIndex of pagesToWatermark) {
      const page = pdf.getPage(pageIndex);
      const { width, height } = page.getSize();

      let x, y, rotation = 0;

      switch (data.position) {
        case 'center':
          x = width / 2;
          y = height / 2;
          break;
        case 'diagonal':
          x = width / 2;
          y = height / 2;
          rotation = 45;
          break;
        case 'top-left':
          x = 50;
          y = height - 50;
          break;
        case 'top-center':
          x = width / 2;
          y = height - 50;
          break;
        case 'top-right':
          x = width - 50;
          y = height - 50;
          break;
        case 'bottom-left':
          x = 50;
          y = 50;
          break;
        case 'bottom-center':
          x = width / 2;
          y = 50;
          break;
        case 'bottom-right':
          x = width - 50;
          y = 50;
          break;
        default:
          x = width / 2;
          y = height / 2;
      }

      page.drawText(data.text, {
        x,
        y,
        size: data.fontSize,
        font,
        color: rgb(color.r, color.g, color.b),
        opacity: data.opacity,
        rotate: degrees(rotation)
      });
    }

    const watermarkedPdfBytes = await pdf.save();
    fs.writeFileSync(data.outputPath, watermarkedPdfBytes);

    return {
      success: true,
      message: `Successfully added watermark to ${pagesToWatermark.length} page(s)`
    };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

async function pdfEncrypt(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes);

    const encryptedPdfBytes = await pdf.save({
      userPassword: data.userPassword,
      ownerPassword: data.ownerPassword || data.userPassword,
      permissions: {
        printing: data.permissions.printing ? 'highResolution' : 'lowResolution',
        modifying: data.permissions.modifying,
        copying: data.permissions.copying,
        annotating: data.permissions.annotating,
        fillingForms: data.permissions.fillingForms,
        contentAccessibility: data.permissions.contentAccessibility,
        documentAssembly: data.permissions.documentAssembly
      }
    });

    fs.writeFileSync(data.outputPath, encryptedPdfBytes);

    return { success: true, message: 'Successfully added password protection to PDF' };
  } catch (error) {
    if (error.message.includes('encrypt') || error.message.includes('password')) {
      return {
        success: false,
        error: 'PDF encryption requires pdf-lib with encryption support. This feature may not be available in the current version.'
      };
    }
    return { success: false, error: error.message };
  }
}

async function pdfDecrypt(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const pdf = await PDFDocument.load(pdfBytes, { password: data.password });

    const decryptedPdfBytes = await pdf.save();
    fs.writeFileSync(data.outputPath, decryptedPdfBytes);

    return { success: true, message: 'Successfully removed password protection from PDF' };
  } catch (error) {
    if (error.message.includes('password') || error.message.includes('encrypted')) {
      return { success: false, error: 'Incorrect password or PDF is not encrypted' };
    }
    return { success: false, error: error.message };
  }
}

async function pdfSetPermissions(data) {
  try {
    const pdfBytes = fs.readFileSync(data.inputPath);
    const loadOptions = data.currentPassword ? { password: data.currentPassword } : {};
    const pdf = await PDFDocument.load(pdfBytes, loadOptions);

    const newPdfBytes = await pdf.save({
      ownerPassword: data.ownerPassword,
      permissions: {
        printing: data.permissions.printing ? 'highResolution' : 'lowResolution',
        modifying: data.permissions.modifying,
        copying: data.permissions.copying,
        annotating: data.permissions.annotating,
        fillingForms: data.permissions.fillingForms,
        contentAccessibility: data.permissions.contentAccessibility,
        documentAssembly: data.permissions.documentAssembly
      }
    });

    fs.writeFileSync(data.outputPath, newPdfBytes);

    return { success: true, message: 'Successfully updated PDF permissions' };
  } catch (error) {
    if (error.message.includes('encrypt') || error.message.includes('permission')) {
      return {
        success: false,
        error: 'PDF permissions require pdf-lib with encryption support. This feature may not be available in the current version.'
      };
    }
    return { success: false, error: error.message };
  }
}

function executeOperation(operation, data) {
  switch (operation) {
    case 'merge': return pdfMerge(data);
    case 'split': return pdfSplit(data);
    case 'compress': return pdfCompress(data);
    case 'rotate': return pdfRotate(data);
    case 'delete': return pdfDeletePages(data);
    case 'reorder': return pdfReorder(data);
    case 'watermark': return pdfWatermark(data);
    case 'encrypt': return pdfEncrypt(data);
    case 'decrypt': return pdfDecrypt(data);
    case 'permissions': return pdfSetPermissions(data);
    default: return Promise.resolve({ success: false, error: `Unknown operation: ${operation}` });
  }
}

async function getPageCount(filePath) {
  const pdfBytes = fs.readFileSync(filePath);
  const pdf = await PDFDocument.load(pdfBytes);
  return pdf.getPageCount();
}

module.exports = {
  parsePageRanges,
  hexToRgb,
  pdfMerge,
  pdfSplit,
  pdfCompress,
  pdfRotate,
  pdfDeletePages,
  pdfReorder,
  pdfWatermark,
  pdfEncrypt,
  pdfDecrypt,
  pdfSetPermissions,
  executeOperation,
  getPageCount
};
