package at.procon.ted.service.attachment;

import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.util.Set;

/**
 * Service for extracting text content from PDF files.
 * Uses Apache PDFBox for PDF parsing and text extraction.
 *
 * @author Martin.Schweitzer@procon.co.at and claude.ai
 */
@Service
@Slf4j
public class PdfExtractionService implements AttachmentExtractor {

    private static final Set<String> SUPPORTED_EXTENSIONS = Set.of("pdf");
    private static final Set<String> SUPPORTED_MIME_TYPES = Set.of(
            "application/pdf",
            "application/x-pdf"
    );

    @Override
    public Set<String> getSupportedExtensions() {
        return SUPPORTED_EXTENSIONS;
    }

    @Override
    public Set<String> getSupportedMimeTypes() {
        return SUPPORTED_MIME_TYPES;
    }

    @Override
    public boolean canHandle(String filename, String contentType) {
        if (filename != null) {
            String lowerFilename = filename.toLowerCase();
            if (SUPPORTED_EXTENSIONS.stream().anyMatch(ext -> lowerFilename.endsWith("." + ext))) {
                return true;
            }
        }
        if (contentType != null) {
            String lowerContentType = contentType.toLowerCase().split(";")[0].trim();
            return SUPPORTED_MIME_TYPES.contains(lowerContentType);
        }
        return false;
    }

    @Override
    public ExtractionResult extract(byte[] data, String filename, String contentType) {
        if (data == null || data.length == 0) {
            return ExtractionResult.failure("Empty PDF data");
        }

        log.debug("Extracting text from PDF: {} ({} bytes)", filename, data.length);

        try (PDDocument document = Loader.loadPDF(data)) {
            // Check if document is encrypted
            if (document.isEncrypted()) {
                log.warn("PDF is encrypted, attempting to decrypt with empty password: {}", filename);
                try {
                    document.setAllSecurityToBeRemoved(true);
                } catch (Exception e) {
                    return ExtractionResult.failure("PDF is encrypted and cannot be decrypted: " + e.getMessage());
                }
            }

            PDFTextStripper stripper = new PDFTextStripper();
            stripper.setSortByPosition(true);

            String text = stripper.getText(document);

            // Clean up extracted text
            text = cleanExtractedText(text);

            int pageCount = document.getNumberOfPages();
            log.info("Successfully extracted {} characters from {} pages of PDF: {}",
                    text.length(), pageCount, filename);

            return ExtractionResult.success(text);

        } catch (Exception e) {
            log.error("Failed to extract text from PDF '{}': {}", filename, e.getMessage(), e);
            return ExtractionResult.failure("PDF extraction failed: " + e.getMessage());
        }
    }

    /**
     * Clean up extracted text by removing excessive whitespace and normalizing line breaks.
     */
    private String cleanExtractedText(String text) {
        if (text == null) {
            return "";
        }

        // Normalize line breaks
        text = text.replaceAll("\r\n", "\n");
        text = text.replaceAll("\r", "\n");

        // Remove excessive blank lines (more than 2 consecutive)
        text = text.replaceAll("\n{3,}", "\n\n");

        // Remove trailing whitespace from each line
        text = text.replaceAll("[ \t]+\n", "\n");

        // Trim leading/trailing whitespace
        text = text.trim();

        return text;
    }
}
