package com.easyagents.federation.sql.source;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;

/**
 * 防止延迟 Definition 复活的数据源删除墓碑。
 *
 * @param sourceId 数据源标识
 * @param revision 删除版本
 * @param checksum 墓碑校验和
 */
public record SourceTombstone(
    SourceId sourceId,
    long revision,
    String checksum
) implements FederationSourceState {

    /**
     * 校验墓碑状态。
     */
    public SourceTombstone {
        if (sourceId == null) {
            throw new IllegalArgumentException("sourceId must not be null");
        }
        if (revision < 0) {
            throw new IllegalArgumentException("revision must not be negative");
        }
        if (checksum == null || checksum.isBlank()) {
            throw new IllegalArgumentException("checksum must not be blank");
        }
        if (!checksum.equals(expectedChecksum(sourceId, revision))) {
            throw new IllegalArgumentException("checksum does not match source tombstone");
        }
    }

    /**
     * 创建具有稳定校验和的墓碑。
     *
     * @param sourceId 数据源标识
     * @param revision 删除版本
     * @return 墓碑
     */
    public static SourceTombstone of(SourceId sourceId, long revision) {
        if (sourceId == null) {
            throw new IllegalArgumentException("sourceId must not be null");
        }
        if (revision < 0) {
            throw new IllegalArgumentException("revision must not be negative");
        }
        return new SourceTombstone(sourceId, revision, expectedChecksum(sourceId, revision));
    }

    private static String expectedChecksum(SourceId sourceId, long revision) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] sourceBytes = sourceId.value().getBytes(StandardCharsets.UTF_8);
            digest.update("federation-source-tombstone-v1".getBytes(StandardCharsets.UTF_8));
            digest.update(ByteBuffer.allocate(Integer.BYTES).putInt(sourceBytes.length).array());
            digest.update(sourceBytes);
            digest.update(ByteBuffer.allocate(Long.BYTES).putLong(revision).array());
            return HexFormat.of().formatHex(digest.digest());
        } catch (NoSuchAlgorithmException exception) {
            throw new IllegalStateException("SHA-256 is not available", exception);
        }
    }
}
