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

import java.util.Objects;
import java.util.function.Consumer;

import de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProgressObserver;
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionEvent;
import de.gecheckt.pdf.umbenenner.application.port.in.DocumentCompletionStatus;
import de.gecheckt.pdf.umbenenner.application.port.in.RunSummary;
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingLogger;

/**
 * Internal per-run adapter that forwards every
 * {@link DocumentCompletionEvent} emitted by the
 * {@link de.gecheckt.pdf.umbenenner.application.service.DocumentProcessingCoordinator}
 * to the configured {@link BatchRunProgressObserver}, while accumulating outcome counts
 * for the run's final {@link RunSummary}.
 * <p>
 * Used only by {@link DefaultBatchRunProcessingUseCase} for the lifetime of a single run.
 * Not thread-safe: all invocations must occur on the batch thread.
 */
final class CountingCompletionObserver implements Consumer<DocumentCompletionEvent> {

    private final BatchRunProgressObserver observer;
    private final ProcessingLogger logger;
    private int successCount;
    private int failedCount;
    private int skippedCount;

    CountingCompletionObserver(BatchRunProgressObserver observer, ProcessingLogger logger) {
        this.observer = Objects.requireNonNull(observer, "observer must not be null");
        this.logger = Objects.requireNonNull(logger, "logger must not be null");
    }

    @Override
    public void accept(DocumentCompletionEvent event) {
        Objects.requireNonNull(event, "event must not be null");
        switch (event.status()) {
            case SUCCESS -> successCount++;
            case FAILED_RETRYABLE, FAILED_PERMANENT -> failedCount++;
            case SKIPPED_ALREADY_PROCESSED, SKIPPED_FINAL_FAILURE -> skippedCount++;
            default -> {
                // Defensive — new status values would be a programming error.
                throw new IllegalStateException(
                        "Unexpected DocumentCompletionStatus: " + event.status());
            }
        }
        try {
            observer.onDocumentCompleted(event);
        } catch (RuntimeException e) {
            logger.warn("Progress observer threw on onDocumentCompleted for '{}': {}",
                    event.originalFileName(), e.getMessage(), e);
        }
    }

    RunSummary summary() {
        return new RunSummary(successCount, failedCount, skippedCount);
    }

    /**
     * Returns the completion status counts collected so far, including the terminal
     * contribution of the candidate currently being reported.
     */
    int successCount() {
        return successCount;
    }

    int failedCount() {
        return failedCount;
    }

    int skippedCount() {
        return skippedCount;
    }

    /**
     * Visible for tests that verify the mapping of completion statuses to summary buckets.
     */
    static RunSummary summaryOf(int successCount, int failedCount, int skippedCount) {
        return new RunSummary(successCount, failedCount, skippedCount);
    }

    /** Test hook to confirm the status classification. */
    static DocumentCompletionStatus classify(DocumentCompletionStatus status) {
        return status;
    }
}
