001package gudusoft.gsqlparser.slpc.adapter;
002
003import gudusoft.gsqlparser.dlineage.dataflow.model.xml.dataflow;
004import gudusoft.gsqlparser.slpc.json.SlpcJson;
005
006import java.nio.charset.StandardCharsets;
007import java.security.MessageDigest;
008import java.security.NoSuchAlgorithmException;
009import java.util.Arrays;
010
011/**
012 * Builds SLPC twice from the exact same completed dataflow instance and binds
013 * the caller's already-produced legacy output to the comparison report.
014 */
015public final class LegacyDualBuildHarness {
016    private final LegacyDlineageAdapter adapter;
017
018    public LegacyDualBuildHarness() { this(new LegacyDlineageAdapter()); }
019    public LegacyDualBuildHarness(LegacyDlineageAdapter adapter) { this.adapter = adapter; }
020
021    public LegacyDualBuildResult compare(dataflow completedResult, String legacyOutput,
022            LegacyAdapterContext context) {
023        if (legacyOutput == null) throw new IllegalArgumentException("legacy output from the same analysis must not be null");
024        LegacyAdaptation first = adapter.adapt(completedResult, context);
025        LegacyAdaptation second = adapter.adapt(completedResult, context);
026        byte[] firstBytes = SlpcJson.canonicalBytes(first.document());
027        byte[] secondBytes = SlpcJson.canonicalBytes(second.document());
028        DeterminismReport report = new DeterminismReport(Arrays.equals(firstBytes, secondBytes), sha256(firstBytes),
029                sha256(secondBytes), sha256(legacyOutput.getBytes(StandardCharsets.UTF_8)));
030        return new LegacyDualBuildResult(first, report);
031    }
032
033    private static String sha256(byte[] bytes) {
034        try {
035            byte[] digest = MessageDigest.getInstance("SHA-256").digest(bytes);
036            StringBuilder result = new StringBuilder();
037            for (byte value : digest) result.append(String.format("%02x", value & 255));
038            return result.toString();
039        } catch (NoSuchAlgorithmException impossible) { throw new IllegalStateException(impossible); }
040    }
041}