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

import java.util.Objects;

/**
 * Unique, stable identity of a document derived exclusively from its binary content.
 * <p>
 * A {@code DocumentFingerprint} is computed once per file read and used as the primary
 * key for all subsequent persistence lookups and history entries. It is independent of
 * the file name, path, or any metadata — only the raw file content determines the value.
 * <p>
 * <strong>Identification semantics:</strong>
 * <ul>
 *   <li>Two files with identical content have the same fingerprint and are treated as
 *       the same document, regardless of their location or name.</li>
 *   <li>A file whose content has changed produces a different fingerprint and is treated
 *       as a new, independent document (new processing record).</li>
 * </ul>
 * <p>
 * <strong>Architecture boundary:</strong> The hashing algorithm (SHA-256) and all
 * file I/O required to compute the fingerprint are strictly confined to the
 * {@code adapter-out} layer. Domain and Application only hold and compare the resulting
 * hex string; they never access the filesystem or perform cryptographic operations.
 * <p>
 * <strong>Pre-fingerprint failures:</strong> If computing the fingerprint fails
 * (e.g. due to an I/O error), no {@code DocumentFingerprint} is created and the failure
 * is not historised in SQLite. The attempt is treated as a non-identifiable run event,
 * not as a documentable processing attempt.
 *
 * @param sha256Hex lowercase hex encoding of the SHA-256 digest (exactly 64 characters,
 *                  characters {@code [0-9a-f]})
 */
public record DocumentFingerprint(String sha256Hex) {

    /**
     * Compact constructor that validates the hex string format.
     *
     * @param sha256Hex lowercase hex encoding of the SHA-256 digest
     * @throws NullPointerException     if {@code sha256Hex} is null
     * @throws IllegalArgumentException if {@code sha256Hex} is not exactly 64 lowercase hex characters
     */
    public DocumentFingerprint {
        Objects.requireNonNull(sha256Hex, "sha256Hex must not be null");
        if (sha256Hex.length() != 64 || !sha256Hex.matches("[0-9a-f]{64}")) {
            throw new IllegalArgumentException(
                    "sha256Hex must be a 64-character lowercase hex string, but was: '"
                            + sha256Hex + "'");
        }
    }
}
