package com.cameleer.license.minter;

import com.cameleer.server.core.license.LicenseInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
import java.util.TreeMap;

public final class LicenseMinter {

    private static final ObjectMapper MAPPER = new ObjectMapper()
            .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

    private LicenseMinter() {}

    public static String mint(LicenseInfo info, PrivateKey ed25519PrivateKey) {
        byte[] payload = canonicalPayload(info);
        try {
            Signature signer = Signature.getInstance("Ed25519");
            signer.initSign(ed25519PrivateKey);
            signer.update(payload);
            byte[] sig = signer.sign();
            return Base64.getEncoder().encodeToString(payload) + "." + Base64.getEncoder().encodeToString(sig);
        } catch (Exception e) {
            throw new IllegalStateException("Failed to sign license", e);
        }
    }

    static byte[] canonicalPayload(LicenseInfo info) {
        ObjectNode root = MAPPER.createObjectNode();
        root.put("exp", info.expiresAt().getEpochSecond());
        root.put("gracePeriodDays", info.gracePeriodDays());
        root.put("iat", info.issuedAt().getEpochSecond());
        if (info.label() != null) {
            root.put("label", info.label());
        }
        root.put("licenseId", info.licenseId().toString());
        ObjectNode limits = MAPPER.createObjectNode();
        new TreeMap<>(info.limits()).forEach(limits::put);
        root.set("limits", limits);
        root.put("tenantId", info.tenantId());
        try {
            return MAPPER.writeValueAsBytes(root);
        } catch (Exception e) {
            throw new IllegalStateException("Failed to serialize license payload", e);
        }
    }
}
