package de.gecheckt.pdf.umbenenner.bootstrap.e2e;

import java.util.concurrent.atomic.AtomicInteger;

import de.gecheckt.pdf.umbenenner.application.port.out.AiInvocationPort;
import de.gecheckt.pdf.umbenenner.application.port.out.AiInvocationResult;
import de.gecheckt.pdf.umbenenner.application.port.out.AiInvocationSuccess;
import de.gecheckt.pdf.umbenenner.application.port.out.AiInvocationTechnicalFailure;
import de.gecheckt.pdf.umbenenner.domain.model.AiRawResponse;
import de.gecheckt.pdf.umbenenner.domain.model.AiRequestRepresentation;

/**
 * Configurable test double for {@link AiInvocationPort}.
 * <p>
 * Replaces the real HTTP-based AI adapter in end-to-end tests so that the processing
 * pipeline can be exercised without real network calls. Supports two response modes:
 * <ul>
 *   <li><strong>Success mode</strong> (default): returns a structurally valid JSON response
 *       containing configurable {@code title} and {@code date} fields. This produces a
 *       {@code PROPOSAL_READY} outcome when the response passes validation.</li>
 *   <li><strong>Technical failure mode</strong>: returns an {@link AiInvocationTechnicalFailure},
 *       simulating network errors or service unavailability. This produces a
 *       {@code FAILED_RETRYABLE} (transient) outcome.</li>
 * </ul>
 * <p>
 * The stub tracks the total number of invocations so that tests can verify whether
 * the AI pipeline was called at all (e.g. confirming that a {@code PROPOSAL_READY}
 * finalization skips the AI call).
 */
final class StubAiInvocationPort implements AiInvocationPort {

    private final AtomicInteger invocationCount = new AtomicInteger(0);

    private volatile boolean returnTechnicalFailure = false;
    private volatile String title = "Stromabrechnung";
    private volatile String date = "2024-01-15";
    private volatile String reasoning = "Testdokument fuer End-to-End-Tests.";

    /**
     * Configures the stub to return a valid naming proposal with the given title and date.
     *
     * @param title the document title (must pass validation: max 20 chars, no special chars)
     * @param date  the document date in {@code YYYY-MM-DD} format, or {@code null} to omit
     */
    void configureSuccess(String title, String date) {
        this.title = title;
        this.date = date;
        this.returnTechnicalFailure = false;
    }

    /**
     * Configures the stub to return a transient technical failure on every invocation.
     * The failure reason is {@code STUB_FAILURE}.
     */
    void configureTechnicalFailure() {
        this.returnTechnicalFailure = true;
    }

    /**
     * Resets the stub to its default success configuration with title "Stromabrechnung"
     * and date "2024-01-15", and clears the invocation counter.
     */
    void reset() {
        this.title = "Stromabrechnung";
        this.date = "2024-01-15";
        this.reasoning = "Testdokument fuer End-to-End-Tests.";
        this.returnTechnicalFailure = false;
        invocationCount.set(0);
    }

    /**
     * Returns the total number of times {@link #invoke} was called since construction
     * or the last {@link #reset()}.
     */
    int invocationCount() {
        return invocationCount.get();
    }

    /**
     * Resets the invocation counter to zero without changing response configuration.
     */
    void resetInvocationCount() {
        invocationCount.set(0);
    }

    /**
     * Returns either a success response or a technical failure, depending on current configuration.
     * Increments the invocation counter on every call.
     */
    @Override
    public AiInvocationResult invoke(AiRequestRepresentation request) {
        invocationCount.incrementAndGet();

        if (returnTechnicalFailure) {
            return new AiInvocationTechnicalFailure(
                    request,
                    "STUB_FAILURE",
                    "Test stub: configured to return technical failure");
        }

        String dateField = (date != null) ? "\"date\": \"" + date + "\", " : "";
        String rawJson = "{"
                + dateField
                + "\"title\": \"" + title + "\", "
                + "\"reasoning\": \"" + reasoning + "\""
                + "}";
        return new AiInvocationSuccess(request, new AiRawResponse(rawJson),
                de.gecheckt.pdf.umbenenner.application.dto.AiUsageMetadata.empty());
    }
}
