/*
 * 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.SecretKeySpec;
import java.security.SecureRandom;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Base64;
import javax.crypto.spec.IvParameterSpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.time.*;
import java.util.*;



public class QrCryptoService {

    private static final byte[] AES_KEY = hexToBytes("3031323334353637383961626364656630313233343536373839616263646566");
    private static final Duration CLOCK_SKEW = Duration.ofSeconds(60);


    public static String createEncryptedQr(String uid, OffsetDateTime expiresAt) throws GeneralSecurityException {
        String payload = uid + "|" + expiresAt.toString();
        byte[] iv = SecureRandom.getInstanceStrong().generateSeed(16);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(AES_KEY, "AES"), new IvParameterSpec(iv));
        byte[] encrypted = cipher.doFinal(payload.getBytes(StandardCharsets.UTF_8));

        String encryptedBase64 = Base64.getEncoder().encodeToString(encrypted);
        String ivBase64 = Base64.getEncoder().encodeToString(iv);

        return ivBase64 + "|" + encryptedBase64;
    }

    public static List<String> decryptAndValidate(String qrRaw) {
        List<String> resultData = new ArrayList<>();
        try {
            String[] parts = qrRaw.split("\\|", 2);
            if (parts.length != 2) {
                throw new IllegalArgumentException("Formato QR non valido. Atteso: IV|payload");
            }

            byte[] iv = Base64.getDecoder().decode(parts[0]);
            byte[] ciphertext = Base64.getDecoder().decode(parts[1]);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(AES_KEY, "AES"), new IvParameterSpec(iv));
            byte[] decrypted = cipher.doFinal(ciphertext);

            String payload = new String(decrypted, StandardCharsets.UTF_8);
            ValidationResult result = validatePayload(payload);

            if (result.valid()) {
                resultData.add("VALID");
                resultData.add(result.uid());
            } else {
                resultData.add("NOT VALID");
                resultData.add("Errore validazione QR code: " + result.reason());
            }

        } catch (Exception e) {
            resultData.add("NOT VALID");
            resultData.add("Errore di decifratura o struttura non valida. QR letto: " + qrRaw);
            resultData.add(e.toString());
        }

        return resultData;
    }


    private static ValidationResult validatePayload(String payload) {
        try {
            String[] parts = payload.split("\\|", 2);
            if (parts.length != 2) {
                return ValidationResult.invalid("Payload malformato: atteso UID|dataOra");
            }

            String uid = parts[0].trim();
            String dateTimeStr = parts[1].trim();

            if (!uid.matches("[A-Z0-9]{16}")) {
                return ValidationResult.invalid("Formato UID non valido");
            }

            OffsetDateTime expiresAt = OffsetDateTime.parse(dateTimeStr);
            Instant now = Instant.now();
            Instant exp = expiresAt.toInstant();

            if (now.minus(CLOCK_SKEW).isAfter(exp)) {
                return ValidationResult.invalid("QR scaduto");
            }

            return ValidationResult.valid(uid, exp);

        } catch (Exception e) {
            return ValidationResult.invalid("Errore di validazione QR Code: Payload malformato o data non valida");
        }
    }

    public static byte[] hexToBytes(String hex) {
        return new BigInteger(hex, 16).toByteArray().length == 33
                ? Arrays.copyOfRange(new BigInteger(hex, 16).toByteArray(), 1, 33)
                : new BigInteger(hex, 16).toByteArray();
    }

  
    public record ValidationResult(boolean valid, String reason, String uid, Instant expiresAt) {

        public static ValidationResult valid(String uid, Instant expiresAt) {
            return new ValidationResult(true, null, uid, expiresAt);
        }

        public static ValidationResult invalid(String reason) {
            return new ValidationResult(false, reason, null, null);
        }
    }

    public static void main(String[] args) throws Exception {
        List<String> dataResult = new ArrayList<>();
        OffsetDateTime now = OffsetDateTime.now().withNano(0);
        OffsetDateTime expiration = now.plusSeconds(CLOCK_SKEW.getSeconds());

        //String qr = createEncryptedQr("TSTTST91A48A271O", expiration);
        //String qr = "eyJpdiI6Ik0xTVJvR3dMbm40UGFMalFEVUh5M1E9PSIsImRhdGEiOiJSVERTTkFURi8wK0lrekFGVVRaSkMrb1Y5QWVZcFRnMFFVKzgzY25QUVgrM2ZMVkRMV3kyOFRsMnBIQTlBRWVGTFQvK0pxSWNtblBYRnBjMys5T0tVWHJpc3FQc1VHazUxRzFpSERSOFJ1eEFCSWhPaTZlamlkdHU4d090WmRzY2F2Y0FRbmNESTd3bGxJNWgvOFFmZnc9PSJ9";
        String qr = "Z8j6FyrmwmSTBYs4iOWTEg==|WKTaAvEqlC+RYW3Ix4ftJcqgDriqdk7pv+U5Aclhmgb70n8y9447wRV6MXW5ikPN";
        System.out.println("QR generato:\n" + qr + "\n");

        dataResult = decryptAndValidate(qr);
        System.out.println("Verifica:\n" + dataResult);
    }
}
