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

import java.time.Instant;
import java.util.Objects;

/**
 * Schreib- und Validierungs-DTO fuer Modell-Preise.
 *
 * <p>Wird im {@code ManageModelPricesUseCase} fuer Inserts und Updates
 * verwendet. Im Gegensatz zum {@link ModelPriceView} sind alle Felder
 * inklusive {@link #updatedAt()} non-null. Validierung erfolgt im
 * Konstruktor; ein konstruiertes Objekt ist ein gueltiger Schreibwert.
 *
 * <p>Wertebereiche:
 * <ul>
 *   <li>{@code priceInputPerTokenNanoUsd} und {@code priceOutputPerTokenNanoUsd}:
 *       0 bis 100&nbsp;000&nbsp;000 (entspricht $0,10/Token bzw. $100&nbsp;000/1M Tokens)</li>
 *   <li>{@code currency}: ausschlie&szlig;lich {@code "USD"}</li>
 * </ul>
 *
 * @param provider                       Provider-Identifikator (z.B. {@code "openai-compatible"} oder {@code "claude"}); nicht leer
 * @param modelName                      Modellname; nicht leer
 * @param priceInputPerTokenNanoUsd      Input-Preis in Nano-USD pro Token; 0..100_000_000
 * @param priceOutputPerTokenNanoUsd     Output-Preis in Nano-USD pro Token; 0..100_000_000
 * @param currency                       Waehrung; nur {@code "USD"} zulaessig
 * @param updatedAt                      Zeitpunkt der letzten Aktualisierung; non-null
 */
public record ModelPriceEntry(
        String provider,
        String modelName,
        long priceInputPerTokenNanoUsd,
        long priceOutputPerTokenNanoUsd,
        String currency,
        Instant updatedAt) {

    /** Maximaler erlaubter Preis pro Token in Nano-USD ($0,10 pro Token). */
    public static final long MAX_PRICE_PER_TOKEN_NANO_USD = 100_000_000L;

    /**
     * Kompakter Konstruktor mit umfassender Validierung.
     *
     * @throws NullPointerException     wenn {@code provider}, {@code modelName} oder {@code updatedAt} {@code null} sind
     * @throws IllegalArgumentException bei leerem Provider/Modellname, negativen Preisen, zu hohen Preisen oder anderer Waehrung als USD
     */
    public ModelPriceEntry {
        Objects.requireNonNull(provider, "provider");
        Objects.requireNonNull(modelName, "modelName");
        Objects.requireNonNull(updatedAt, "updatedAt");
        if (provider.isBlank()) {
            throw new IllegalArgumentException("provider darf nicht leer sein");
        }
        if (modelName.isBlank()) {
            throw new IllegalArgumentException("modelName darf nicht leer sein");
        }
        if (priceInputPerTokenNanoUsd < 0L) {
            throw new IllegalArgumentException("Input-Preis darf nicht negativ sein");
        }
        if (priceOutputPerTokenNanoUsd < 0L) {
            throw new IllegalArgumentException("Output-Preis darf nicht negativ sein");
        }
        if (priceInputPerTokenNanoUsd > MAX_PRICE_PER_TOKEN_NANO_USD) {
            throw new IllegalArgumentException("Input-Preis ueberschreitet Maximum");
        }
        if (priceOutputPerTokenNanoUsd > MAX_PRICE_PER_TOKEN_NANO_USD) {
            throw new IllegalArgumentException("Output-Preis ueberschreitet Maximum");
        }
        if (!"USD".equals(currency)) {
            throw new IllegalArgumentException("Nur Waehrung USD unterstuetzt");
        }
    }
}
