package de.gecheckt.pdf.umbenenner.application.service;

import java.util.Objects;

import de.gecheckt.pdf.umbenenner.application.config.RuntimeConfiguration;
import de.gecheckt.pdf.umbenenner.domain.model.DocumentProcessingOutcome;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionContentError;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionResult;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionSuccess;
import de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionTechnicalError;
import de.gecheckt.pdf.umbenenner.domain.model.PreCheckFailed;
import de.gecheckt.pdf.umbenenner.domain.model.PreCheckFailureReason;
import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
import de.gecheckt.pdf.umbenenner.domain.model.TechnicalDocumentError;

/**
 * Orchestrates document processing pipeline: extraction → pre-checks → outcome classification.
 * <p>
 * Converts technical extraction results into processing outcomes through this pipeline:
 * <ol>
 *   <li>If extraction fails (technical): {@link TechnicalDocumentError}</li>
 *   <li>If extraction fails (content): {@link PreCheckFailed}</li>
 *   <li>If extraction succeeds: Evaluate pre-checks via {@link PreCheckEvaluator}</li>
 * </ol>
 * <p>
 * This service produces {@link DocumentProcessingOutcome}, a sealed interface that covers
 * all document processing outcomes:
 * <ul>
 *   <li>Pre-check passed (document ready for further processing)</li>
 *   <li>Pre-check failed (deterministic content error: no usable text, page limit exceeded, content not extractable)</li>
 *   <li>Technical document error (I/O, access, PDF parsing, etc.)</li>
 * </ul>
 * <p>
 * This service is stateless and thread-safe.
 */
public class DocumentProcessingService {

    /**
     * Processes a document candidate through the complete pipeline.
     * <p>
     * Pipeline:
     * <ol>
     *   <li>Extract text and page count from the PDF candidate</li>
     *   <li>If extraction fails (technical): classify as technical document error</li>
     *   <li>If extraction fails (content): classify as pre-check failed (deterministic content error)</li>
     *   <li>If extraction succeeds: evaluate pre-checks</li>
     * </ol>
     *
     * @param candidate the document candidate to process
     * @param extractionResult the result from PDF extraction (from {@link de.gecheckt.pdf.umbenenner.application.port.out.PdfTextExtractionPort})
     * @param runtimeConfig the runtime configuration (used for pre-check validation)
     * @return the complete processing outcome (implementing {@link DocumentProcessingOutcome})
     * @throws NullPointerException if any parameter is null
     */
    public static DocumentProcessingOutcome processDocument(
            SourceDocumentCandidate candidate,
            PdfExtractionResult extractionResult,
            RuntimeConfiguration runtimeConfig) {

        Objects.requireNonNull(candidate, "candidate must not be null");
        Objects.requireNonNull(extractionResult, "extractionResult must not be null");
        Objects.requireNonNull(runtimeConfig, "runtimeConfig must not be null");

        return switch (extractionResult) {
            case PdfExtractionSuccess success ->
                // Extraction succeeded: evaluate pre-checks
                PreCheckEvaluator.evaluate(candidate, success, runtimeConfig);

            case PdfExtractionContentError contentError ->
                // PDF content not extractable: classify as pre-check failed (deterministic content error)
                new PreCheckFailed(candidate, PreCheckFailureReason.CONTENT_NOT_EXTRACTABLE);

            case PdfExtractionTechnicalError technicalError ->
                // Technical failure during extraction: potentially retryable
                new TechnicalDocumentError(candidate, technicalError.errorMessage(), technicalError.cause());
        };
    }

    private DocumentProcessingService() {
        // Static utility class – no instances
    }
}