/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package puntocassa.utils;

/**
 *
 * @author assis
 */
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.OffsetDateTime;
import java.util.Base64;
import org.json.JSONObject;

public class QrCryptoService {

    // Chiave AES 256-bit (32 byte) - hardcoded per test
    private static final byte[] AES_KEY = "0123456789ABCDEF0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);

    // Crea il JSON cifrato da inserire nel QR
    public static String createEncryptedQr(String uid, OffsetDateTime issuedAt, OffsetDateTime expiresAt) throws Exception {
        // Crea il payload JSON con i dati utente
        String payloadJson = new JSONObject()
                .put("uid", uid)
                .put("issued_at", issuedAt.toString())
                .put("expires_at", expiresAt.toString())
                .toString();

        // Genera un Initialization Vector (IV) da 96 bit
        byte[] iv = new byte[12];
        new SecureRandom().nextBytes(iv);

        // Cifra il payload con AES-GCM
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES");
        GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec);
        byte[] encrypted = cipher.doFinal(payloadJson.getBytes(StandardCharsets.UTF_8));

        // Codifica IV e dati cifrati in Base64
        String ivBase64 = Base64.getEncoder().encodeToString(iv);
        String encryptedBase64 = Base64.getEncoder().encodeToString(encrypted);

        // Costruisce il JSON finale con iv e data
        JSONObject qrJson = new JSONObject()
                .put("iv", ivBase64)
                .put("data", encryptedBase64);

        return qrJson.toString(2); // con indentazione
    }

    // Decifra il JSON e verifica se è ancora valido
    public static String decryptAndValidate(String qrJson) throws Exception {
        JSONObject obj = new JSONObject(qrJson);
        byte[] iv = Base64.getDecoder().decode(obj.getString("iv"));
        byte[] encryptedData = Base64.getDecoder().decode(obj.getString("data"));

        // Decrittazione con AES-GCM
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES");
        GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec);
        byte[] decryptedBytes = cipher.doFinal(encryptedData);

        // Parsing del payload decifrato
        JSONObject payload = new JSONObject(new String(decryptedBytes, StandardCharsets.UTF_8));
        String uid = payload.getString("uid");
        OffsetDateTime issuedAt = OffsetDateTime.parse(payload.getString("issued_at"));
        OffsetDateTime expiresAt = OffsetDateTime.parse(payload.getString("expires_at"));
        boolean isExpired = OffsetDateTime.now(expiresAt.getOffset()).isAfter(expiresAt);

        return String.format(
                "Dati decifrati:\n" +
                "- UID: %s\n" +
                "- Emesso: %s\n" +
                "- Scadenza: %s\n" +
                "- Stato: %s\n",
                uid,
                issuedAt,
                expiresAt,
                isExpired ? "SCADUTO" : "VALIDO"
        );
    }

    // Test completo della generazione e verifica
    public static void main(String[] args) throws Exception {
        //data valida
        OffsetDateTime issuedAt = OffsetDateTime.now().withNano(0);
        //data scaduta
        //OffsetDateTime issuedAt = OffsetDateTime.now().minusMinutes(5).withNano(0);
        OffsetDateTime expiresAt = issuedAt.plusSeconds(60);
        String qrJson = createEncryptedQr("TSTTST91A48A271O", issuedAt, expiresAt);

        System.out.println("QR JSON simulato:");
        System.out.println(qrJson);

        System.out.println("\nVerifica decifratura:");
        System.out.println(decryptAndValidate(qrJson));
    }
}
