package de.gecheckt.pdf.umbenenner.domain.model;

import java.util.Objects;

/**
 * Carries the AI-related traceability data produced during an AI naming attempt.
 * <p>
 * This record aggregates the metadata required to persist full AI traceability in
 * the processing attempt history:
 * <ul>
 *   <li>AI infrastructure details (model name, prompt identifier)</li>
 *   <li>Request size metrics (processed pages, sent character count)</li>
 *   <li>Raw AI output (for audit and diagnostics; stored in SQLite, not in log files)</li>
 *   <li>Token-Verbrauch (Standard- und Anthropic-Cache-Tokens) – nullable, da nicht
 *       jeder Provider Token-Counts liefert und einzelne Felder vom Adapter wegen
 *       ungueltiger Werte ({@code null}, &lt; 0, &gt; 10 Mio.) auf {@code null}
 *       gesetzt werden koennen.</li>
 * </ul>
 * <p>
 * This context is produced whenever an AI call is attempted, regardless of whether
 * the call succeeded or failed. Fields that could not be determined (e.g. raw response
 * on connection failure) may be {@code null}.
 *
 * @param modelName                  the AI model name used in the request; never null
 * @param promptIdentifier           stable identifier of the prompt template; never null
 * @param processedPageCount         number of PDF pages included in the extraction; must be &gt;= 1
 * @param sentCharacterCount         number of document-text characters sent to the AI; must be &gt;= 0
 * @param aiRawResponse              the complete raw AI response body; {@code null} if the call did
 *                                   not return a response body (e.g. timeout or connection error)
 * @param inputTokens                Anzahl Standard-Input-Tokens; {@code null} wenn nicht ermittelbar
 * @param outputTokens               Anzahl Standard-Output-Tokens; {@code null} wenn nicht ermittelbar
 * @param cacheCreationInputTokens   Anzahl Cache-Schreib-Tokens (Anthropic); {@code null} bei OpenAI oder fehlend
 * @param cacheReadInputTokens       Anzahl Cache-Lese-Tokens (Anthropic); {@code null} bei OpenAI oder fehlend
 */
public record AiAttemptContext(
        String modelName,
        String promptIdentifier,
        int processedPageCount,
        int sentCharacterCount,
        String aiRawResponse,
        Long inputTokens,
        Long outputTokens,
        Long cacheCreationInputTokens,
        Long cacheReadInputTokens) {

    /**
     * Compact constructor validating mandatory fields.
     *
     * @throws NullPointerException     if {@code modelName} or {@code promptIdentifier} is null
     * @throws IllegalArgumentException if {@code processedPageCount} &lt; 1 or
     *                                  {@code sentCharacterCount} &lt; 0
     */
    public AiAttemptContext {
        Objects.requireNonNull(modelName, "modelName must not be null");
        Objects.requireNonNull(promptIdentifier, "promptIdentifier must not be null");
        if (processedPageCount < 1) {
            throw new IllegalArgumentException(
                    "processedPageCount must be >= 1, but was: " + processedPageCount);
        }
        if (sentCharacterCount < 0) {
            throw new IllegalArgumentException(
                    "sentCharacterCount must be >= 0, but was: " + sentCharacterCount);
        }
    }

    /**
     * Convenience-Konstruktor ohne Token-Felder.
     *
     * <p>Setzt alle vier Token-Felder auf {@code null}. Wird von Aufrufern verwendet,
     * die noch keine Token-Daten beistellen (z.B. KI-Aufrufe ohne usage-Antwort,
     * frueher V3.2-Bestand oder Tests, die das Token-Tracking nicht beruehren).
     *
     * @param modelName          AI model name; never null
     * @param promptIdentifier   stable prompt identifier; never null
     * @param processedPageCount number of PDF pages included; must be &gt;= 1
     * @param sentCharacterCount number of characters sent to AI; must be &gt;= 0
     * @param aiRawResponse      raw AI response body or {@code null}
     */
    public AiAttemptContext(
            String modelName,
            String promptIdentifier,
            int processedPageCount,
            int sentCharacterCount,
            String aiRawResponse) {
        this(modelName, promptIdentifier, processedPageCount, sentCharacterCount, aiRawResponse,
                null, null, null, null);
    }
}
