package com.writeoff.security;

import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.MGF1ParameterSpec;
import java.util.Base64;

@Service
public class LoginPasswordCryptoService {
    public static final String PASSWORD_PREFIX = "rsa:";
    private static final OAEPParameterSpec OAEP_SHA256_MGF1_SHA256 = new OAEPParameterSpec(
            "SHA-256",
            "MGF1",
            MGF1ParameterSpec.SHA256,
            PSource.PSpecified.DEFAULT
    );

    private volatile RSAPublicKey publicKey;
    private volatile RSAPrivateKey privateKey;

    @PostConstruct
    public void init() {
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
            generator.initialize(2048);
            KeyPair keyPair = generator.generateKeyPair();
            this.publicKey = (RSAPublicKey) keyPair.getPublic();
            this.privateKey = (RSAPrivateKey) keyPair.getPrivate();
        } catch (Exception ex) {
            throw new IllegalStateException("Unable to initialize login password crypto service", ex);
        }
    }

    public String getEncodedPublicKey() {
        RSAPublicKey key = publicKey;
        if (key == null) {
            throw new IllegalStateException("Login password public key is not ready");
        }
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    public String unwrapPassword(String password) {
        if (password == null || password.trim().isEmpty()) {
            return password;
        }
        if (!password.startsWith(PASSWORD_PREFIX)) {
            return password;
        }
        String cipherText = password.substring(PASSWORD_PREFIX.length()).trim();
        if (cipherText.isEmpty()) {
            throw new IllegalArgumentException("Encrypted password cannot be empty");
        }
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey, OAEP_SHA256_MGF1_SHA256);
            byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherText));
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception ex) {
            throw new IllegalArgumentException("Unable to decrypt login password", ex);
        }
    }
}
