package stirling.software.SPDF.controller.api;

import java.awt.geom.AffineTransform;
import java.io.IOException;

import org.apache.pdfbox.multipdf.LayerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;

import io.swagger.v3.oas.annotations.Operation;

import lombok.RequiredArgsConstructor;

import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.annotations.api.GeneralApi;
import stirling.software.common.enumeration.ResourceWeight;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.GeneralUtils;
import stirling.software.common.util.TempFileManager;
import stirling.software.common.util.WebResponseUtils;

@GeneralApi
@RequiredArgsConstructor
public class ToSinglePageController {

    private final CustomPDFDocumentFactory pdfDocumentFactory;
    private final TempFileManager tempFileManager;

    @AutoJobPostMapping(
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
            value = "/pdf-to-single-page",
            resourceWeight = ResourceWeight.MEDIUM_WEIGHT)
    @StandardPdfResponse
    @Operation(
            summary = "Convert a multi-page PDF into a single long page PDF",
            description =
                    "This endpoint converts a multi-page PDF document into a single paged PDF"
                            + " document. The width of the single page will be same as the input's"
                            + " width, but the height will be the sum of all the pages' heights."
                            + " Input:PDF Output:PDF Type:SISO")
    public ResponseEntity<Resource> pdfToSinglePage(@ModelAttribute PDFFile request)
            throws IOException {

        // Load the source document
        try (PDDocument sourceDocument = pdfDocumentFactory.load(request)) {
            // Calculate total height and max width
            float totalHeight = 0;
            float maxWidth = 0;
            for (PDPage page : sourceDocument.getPages()) {
                PDRectangle pageSize = page.getMediaBox();
                totalHeight += pageSize.getHeight();
                maxWidth = Math.max(maxWidth, pageSize.getWidth());
            }

            // Create new document and page with calculated dimensions
            try (PDDocument newDocument =
                    pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument)) {
                PDPage newPage = new PDPage(new PDRectangle(maxWidth, totalHeight));
                newDocument.addPage(newPage);

                LayerUtility layerUtility = new LayerUtility(newDocument);
                float yOffset = totalHeight;

                // For each page, copy its content to the new page at the correct offset
                try {
                    layerUtility.wrapInSaveRestore(newPage);
                } catch (NullPointerException e) {
                }

                int pageIndex = 0;
                for (PDPage page : sourceDocument.getPages()) {
                    PDFormXObject form = layerUtility.importPageAsForm(sourceDocument, pageIndex);
                    if (form != null) {
                        AffineTransform af =
                                AffineTransform.getTranslateInstance(
                                        0, yOffset - page.getMediaBox().getHeight());
                        String defaultLayerName = "Layer" + pageIndex;
                        layerUtility.appendFormAsLayer(newPage, form, af, defaultLayerName);
                    }
                    yOffset -= page.getMediaBox().getHeight();
                    pageIndex++;
                }

                return WebResponseUtils.pdfDocToWebResponse(
                        newDocument,
                        GeneralUtils.generateFilename(
                                request.getFileInput().getOriginalFilename(), "_singlePage.pdf"),
                        tempFileManager);
            }
        }
    }
}
