package com.ffii.lioner.modules.lioner.pdf.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.springframework.stereotype.Service;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.utils.PdfMerger;

@Service
public class PdfMergeService {

    // --- ACROFORM REMOVAL HELPER METHOD ---
    
    /**
     * Flattens form fields, preserving their appearance (text/checkmarks) 
     * but making the PDF plain and non-interactive.
     */
    private void flattenPdf(PdfDocument doc) {
        // Get the AcroForm instance for the document. 'true' creates it if none exists.
        PdfAcroForm acroForm = PdfAcroForm.getAcroForm(doc, true);

        // This method automatically converts all field values into static content
        // and removes the form dictionary (making the PDF plain).
        acroForm.flattenFields(); 
    }

    public void removePdfPassword() throws IOException {
        // Load PDF A and PDF B
        //String filePathA = "C:\\dev\\pdf\\pdfA.pdf";
        //File fileA = new File(filePathA);

        String filePathB = "C:\\dev\\pdf\\pdfB.pdf";
        File fileB = new File(filePathB);

        String outputPath = "C:\\dev\\pdf\\pdfOut.pdf";

        try (
            //PDDocument pdfA = Loader.loadPDF(fileA);
            PDDocument pdfB = Loader.loadPDF(fileB);
            
            PDDocument mergedPdf = new PDDocument()) {

            for (int i = 0; i < pdfB.getNumberOfPages(); i++) {
                PDPage page = pdfB.getPage(i);
                mergedPdf.addPage(page);
            }

            //this is for remove the password and copy the whole pdf
            pdfB.setAllSecurityToBeRemoved(true);
            pdfB.save(new File(outputPath));
            
            // Save the merged PDF
            mergedPdf.save(new File(outputPath));
            mergedPdf.close();
        }
    }

    
    public void mergePdfs() throws IOException {
        // This method uses PDFBox and is left unchanged as the focus was iText 7
        String filePathA = "C:\\dev\\pdf\\pdfA.pdf";
        File fileA = new File(filePathA);

        String filePathB = "C:\\dev\\pdf\\pdfB.pdf";
        File fileB = new File(filePathB);

        String outputPath = "C:\\dev\\pdf\\pdfOut.pdf";

        try (
            PDDocument pdfA = Loader.loadPDF(fileA);
            PDDocument pdfB = Loader.loadPDF(fileB);
            
            PDDocument mergedPdf = new PDDocument()) {

            for (int i = 0; i < pdfB.getNumberOfPages(); i++) {
                PDPage page = pdfB.getPage(i);
                mergedPdf.addPage(page);
            }

            mergedPdf.save(new File(outputPath));
        }
    }

    public byte[] flatPdfsItext7(byte[] pdfABytes) throws IOException {
        
        // --- STEP 1: Flatten PDF A and get the modified bytes ---
        byte[] pdfAFlattenedBytes;
        try (PdfReader readerA = new PdfReader(new ByteArrayInputStream(pdfABytes));
             ByteArrayOutputStream tempBaosA = new ByteArrayOutputStream();
             PdfWriter tempWriterA = new PdfWriter(tempBaosA);
             PdfDocument docA_mod = new PdfDocument(readerA, tempWriterA)) {
            
            flattenPdf(docA_mod);
            docA_mod.close(); // IMPORTANT: Close to finalize writing to tempBaosA
            pdfAFlattenedBytes = tempBaosA.toByteArray();
            return tempBaosA.toByteArray();
        }

    }

    public byte[] mergePdfsItext7(String formCode, byte[] pdfABytes, byte[] pdfBBytes) throws IOException {

        // Defined constants for clarity
        final int IDA_SIG_PAGE = 15; // Page to skip for IDA
        final int FNA_SIG_PAGE = 10;  // Page to skip for FNA
        final int HSBC_REP_PAGE = 11; // Page to replace for HSBCFIN
        final int HSBCA31_REP_START = 28; // Start page to replace for HSBCA31 (Page 28)
        final int HSBCA31_REP_END = 29;   // End page to replace for HSBCA31 (Page 29)
        final int HSBCA31_REP_COUNT = 2;  // Number of pages from pdfB to insert
        
        final int MLB03S_REP_PAGE = 9;
        final int MLFNA_REP_PAGE = 4;

        final int SLFNA_REP_PAGE = 5;
        final int SLAPP_REP_PAGE = 17;
        final int SLGII_REP_PAGE = 13;

        // --- STEP 1: Flatten PDF A and get the modified bytes ---
        byte[] pdfAFlattenedBytes;
        try (PdfReader readerA = new PdfReader(new ByteArrayInputStream(pdfABytes));
             ByteArrayOutputStream tempBaosA = new ByteArrayOutputStream();
             PdfWriter tempWriterA = new PdfWriter(tempBaosA);
             PdfDocument docA_mod = new PdfDocument(readerA, tempWriterA)) {
            
            flattenPdf(docA_mod);
            docA_mod.close(); // IMPORTANT: Close to finalize writing to tempBaosA
            pdfAFlattenedBytes = tempBaosA.toByteArray();
        }

        // --- STEP 2: Flatten PDF B and get the modified bytes (if needed) ---
        byte[] pdfBFlattenedBytes = null;
        if (pdfBBytes != null && pdfBBytes.length > 0) {
            try (PdfReader readerB = new PdfReader(new ByteArrayInputStream(pdfBBytes));
                 ByteArrayOutputStream tempBaosB = new ByteArrayOutputStream();
                 PdfWriter tempWriterB = new PdfWriter(tempBaosB);
                 PdfDocument docB_mod = new PdfDocument(readerB, tempWriterB)) {
                
                flattenPdf(docB_mod);
                docB_mod.close(); // IMPORTANT: Close to finalize writing to tempBaosB
                pdfBFlattenedBytes = tempBaosB.toByteArray();
            }
        }

        // --- STEP 3: Perform the merge using the flattened bytes ---
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             PdfWriter writer = new PdfWriter(baos);
             PdfDocument mergedPdf = new PdfDocument(writer);
             PdfReader readerA_merge = new PdfReader(new ByteArrayInputStream(pdfAFlattenedBytes));
             PdfDocument docA = new PdfDocument(readerA_merge)) { 

            // ⭐️ FIX: PdfMerger is NOT AutoCloseable, so we instantiate it here.
            PdfMerger merger = new PdfMerger(mergedPdf);
            
            int totalPagesA = docA.getNumberOfPages();
            
            // --- Multi/Single Page Replacement Logic ---
            int repPage = -1; 
            int repStartA = -1;
            int repEndA = -1;
            int repCountB = -1;
            boolean isMultiPageReplace = false;

            // Single Page Replacements
            if ("MLB03S".equals(formCode)) {
                repPage = MLB03S_REP_PAGE;
            } else if ("MLFNA_EN".equals(formCode) || "MLFNA_CHI".equals(formCode)) {
                repPage = MLFNA_REP_PAGE;
            } else if ("SLFNA_EN".equals(formCode) || "SLFNA_CHI".equals(formCode)) {
                repPage = SLFNA_REP_PAGE;
            } else if ("SLAPP".equals(formCode)) {
                repPage = SLAPP_REP_PAGE;
            } else if ("SLGII".equals(formCode)) {
                repPage = SLGII_REP_PAGE;
            }
            // Multi-Page Replacement HSBCA31
            else if ("HSBCA31".equals(formCode) && totalPagesA >= HSBCA31_REP_END) {
                 isMultiPageReplace = true;
                 repStartA = HSBCA31_REP_START;
                 repEndA = HSBCA31_REP_END;
                 repCountB = HSBCA31_REP_COUNT;
            }

            if ((repPage != -1 && totalPagesA >= repPage) || isMultiPageReplace) {
                
                // Determine start/end pages for copy segments
                int firstSegmentEnd = isMultiPageReplace ? repStartA - 1 : repPage - 1;
                int secondSegmentStart = isMultiPageReplace ? repEndA + 1 : repPage + 1;
                int pagesToInsertB = isMultiPageReplace ? repCountB : 1;

                // A. Copy pages 1 up to the start of replacement
                if (firstSegmentEnd >= 1) {
                    merger.merge(docA, 1, firstSegmentEnd);
                }
                
                // B. Insert replacement pages from PDF B (if available)
                if (pdfBFlattenedBytes != null) {
                    try (PdfReader readerB_merge = new PdfReader(new ByteArrayInputStream(pdfBFlattenedBytes));
                         PdfDocument docB = new PdfDocument(readerB_merge)) {
                        
                        if (docB.getNumberOfPages() >= pagesToInsertB) {
                             merger.merge(docB, 1, pagesToInsertB);
                        }
                    }
                }
                
                // C. Copy pages after replacement through the end
                if (totalPagesA >= secondSegmentStart) {
                    merger.merge(docA, secondSegmentStart, totalPagesA);
                }

            // --- Existing Logic (Skip Pages) ---
            } else if ("IDA".equals(formCode) && totalPagesA >= IDA_SIG_PAGE) {
                // IDA: SKIP page 15
                if (IDA_SIG_PAGE > 1) {
                    merger.merge(docA, 1, IDA_SIG_PAGE - 1);
                }
                if (totalPagesA > IDA_SIG_PAGE) {
                    merger.merge(docA, IDA_SIG_PAGE + 1, totalPagesA);
                }
                
            } else if ("FNA".equals(formCode) && totalPagesA >= FNA_SIG_PAGE) {
                // FNA: SKIP page 10
                if (FNA_SIG_PAGE > 1) {
                    merger.merge(docA, 1, FNA_SIG_PAGE - 1);
                }
                if (totalPagesA > FNA_SIG_PAGE) {
                    merger.merge(docA, FNA_SIG_PAGE + 1, totalPagesA);
                }
                
            } else if ("HSBCFIN".equals(formCode) && totalPagesA >= HSBC_REP_PAGE) {
                // HSBCFIN: REPLACE page 11 with PDF B page 1
                
                if (HSBC_REP_PAGE > 1) {
                    merger.merge(docA, 1, HSBC_REP_PAGE - 1);
                }
                
                if (pdfBFlattenedBytes != null) {
                    try (PdfReader readerB_merge = new PdfReader(new ByteArrayInputStream(pdfBFlattenedBytes));
                          PdfDocument docB = new PdfDocument(readerB_merge)) {
                        merger.merge(docB, 1, 1);
                    }
                }
                
                if (totalPagesA > HSBC_REP_PAGE) {
                    merger.merge(docA, HSBC_REP_PAGE + 1, totalPagesA);
                }

            } else {
                // Default: Copy all pages from docA
                merger.merge(docA, 1, totalPagesA);
            }
            
            // 4. Process PDF B (Only appended if IDA or FNA)
            if (pdfBFlattenedBytes != null) {
                if ("IDA".equals(formCode) || "FNA".equals(formCode)){
                    try (PdfReader readerB_merge = new PdfReader(new ByteArrayInputStream(pdfBFlattenedBytes));
                         PdfDocument docB = new PdfDocument(readerB_merge)) {
                        
                        // Copy ONLY page 1 from docB to append as the last page
                        merger.merge(docB, 1, 1);
                    }
                }
            }

            mergedPdf.close(); 
            return baos.toByteArray();
        }
    }

    public byte[] mergePdf2sItext7(String formCode, byte[] pdfABytes, byte[] pdfBBytes) throws IOException {

        // UPDATED CONSTANTS FOR NEW REQUIREMENTS
        final int MLB03S_REP_START_A = 12;
        final int MLB03S_REP_END_A = 13;
        final int MLB03S_REP_COUNT_B = 2;
        final int SLAPP_REP_START_A = 19;
        final int SLAPP_REP_END_A = 20; 
        final int SLAPP_REP_COUNT_B = 2;
        final int SLGII_REP_START_A = 15;
        final int SLGII_REP_END_A = 16; 
        final int SLGII_REP_COUNT_B = 2;
      
        // --- STEP 1: Flatten PDF A and get the modified bytes ---
        byte[] pdfAFlattenedBytes;
        try (PdfReader readerA = new PdfReader(new ByteArrayInputStream(pdfABytes));
             ByteArrayOutputStream tempBaosA = new ByteArrayOutputStream();
             PdfWriter tempWriterA = new PdfWriter(tempBaosA);
             PdfDocument docA_mod = new PdfDocument(readerA, tempWriterA)) {
            
            flattenPdf(docA_mod);
            docA_mod.close(); // IMPORTANT: Close to finalize writing to tempBaosA
            pdfAFlattenedBytes = tempBaosA.toByteArray();
        }

        // --- STEP 2: Flatten PDF B and get the modified bytes (if needed) ---
        byte[] pdfBFlattenedBytes = null;
        if (pdfBBytes != null && pdfBBytes.length > 0) {
            try (PdfReader readerB = new PdfReader(new ByteArrayInputStream(pdfBBytes));
                 ByteArrayOutputStream tempBaosB = new ByteArrayOutputStream();
                 PdfWriter tempWriterB = new PdfWriter(tempBaosB);
                 PdfDocument docB_mod = new PdfDocument(readerB, tempWriterB)) {
                
                flattenPdf(docB_mod);
                docB_mod.close(); // IMPORTANT: Close to finalize writing to tempBaosB
                pdfBFlattenedBytes = tempBaosB.toByteArray();
            }
        }
        
        // --- STEP 3: Perform the merge using the flattened bytes ---
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
             PdfWriter writer = new PdfWriter(baos);
             PdfDocument mergedPdf = new PdfDocument(writer);
             PdfReader readerA_merge = new PdfReader(new ByteArrayInputStream(pdfAFlattenedBytes));
             PdfDocument docA = new PdfDocument(readerA_merge)) { 

            // ⭐️ FIX: PdfMerger is NOT AutoCloseable, so we instantiate it here.
            PdfMerger merger = new PdfMerger(mergedPdf);

            int totalPagesA = docA.getNumberOfPages();
            
            // --- Multi-page Replacement Forms (SLAPP, SLGII) ---
            int repStartA = -1;
            int repEndA = -1;
            int repCountB = -1;

            if ("SLAPP".equals(formCode)) {
                repStartA = SLAPP_REP_START_A;
                repEndA = SLAPP_REP_END_A;
                repCountB = SLAPP_REP_COUNT_B;
            } else if ("SLGII".equals(formCode)) {
                repStartA = SLGII_REP_START_A;
                repEndA = SLGII_REP_END_A;
                repCountB = SLGII_REP_COUNT_B;
            } else if ("MLB03S".equals(formCode)) {
                repStartA = MLB03S_REP_START_A;
                repEndA = MLB03S_REP_END_A;
                repCountB = MLB03S_REP_COUNT_B;
            }

            if (repStartA != -1 && totalPagesA >= repEndA) {
                
                // A. Copy pages 1 up to (repStartA - 1)
                if (repStartA > 1) {
                    merger.merge(docA, 1, repStartA - 1);
                }

                // B. Insert replacement pages from PDF B (if available)
                if (pdfBFlattenedBytes != null) {
                    try (PdfReader readerB_merge = new PdfReader(new ByteArrayInputStream(pdfBFlattenedBytes));
                         PdfDocument docB = new PdfDocument(readerB_merge)) {
                        
                        // Copy the required number of pages from docB starting from page 1
                        if (docB.getNumberOfPages() >= repCountB) {
                            merger.merge(docB, 1, repCountB);
                        } else {
                            System.err.println("PDF B too short for " + formCode + " replacement.");
                        }
                    }
                }

                // C. Copy pages (repEndA + 1) through the end
                if (totalPagesA > repEndA) {
                    merger.merge(docA, repEndA + 1, totalPagesA);
                }
            
            // --- Single Page Replacement Forms (MLB03S) ---
            /*
            } else if ("MLB03S".equals(formCode) && totalPagesA >= MLB03S_REP_PAGE_A) {
                
                // A. Copy pages 1 up to 11 (MLB03S_REP_PAGE_A - 1)
                if (MLB03S_REP_PAGE_A > 1) {
                    merger.merge(docA, 1, MLB03S_REP_PAGE_A - 1);
                }
                
                // B. Insert replacement page from PDF B (if available)
                if (pdfBFlattenedBytes != null) {
                    try (PdfReader readerB_merge = new PdfReader(new ByteArrayInputStream(pdfBFlattenedBytes));
                         PdfDocument docB = new PdfDocument(readerB_merge)) {
                        
                        // Copy ONLY page 1 from docB
                        if (docB.getNumberOfPages() >= 1) {
                            merger.merge(docB, 1, 1);
                        }
                    }
                }
                
                // C. Copy pages 13 through the end (MLB03S_REP_PAGE_A + 1)
                if (totalPagesA > MLB03S_REP_PAGE_A) {
                    merger.merge(docA, MLB03S_REP_PAGE_A + 1, totalPagesA);
                }
            */
            } else {
                // Default: Copy all pages from docA
                merger.merge(docA, 1, totalPagesA);
            }
            
            mergedPdf.close(); 
            return baos.toByteArray();

        }
    }
}