package api;

import com.sunyard.chsm.enums.AlgMode;
import com.sunyard.chsm.param.*;
import com.sunyard.chsm.utils.CodecUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Collections;

/**
 * @author liulu
 * @since 2024/12/18
 */
@Slf4j
public class SymKeyTest extends BaseTest {

    private static final byte[] plain = new byte[1024 * 7];
    private final static byte[] iv = "ghwikdhj1234713v".getBytes();
    private static Long keyId;

    @BeforeAll
    public static void beforeAll() {
        Arrays.fill(plain, (byte) 0x04);
        keyId = execute("/key/gen", KeyCreateReq.builder().keyTemplateCode(keyTemplate).genNumber(1).build(), Long.class);
        Assertions.assertTrue(keyId > 0);
    }

    @AfterAll
    public static void afterAll() {
        KeyManageReq keyManageReq = new KeyManageReq();
        keyManageReq.setIds(Collections.singletonList(keyId));
        execute("/key/disable", keyManageReq, Void.class);
        execute("/key/destroy", keyManageReq, Void.class);
    }

    @Test
    public void testEncAndDecCBC() {

        SymEncryptReq symEncryptReq = new SymEncryptReq();
        symEncryptReq.setKeyId(keyId);
        symEncryptReq.setPlainData(CodecUtils.encodeBase64(plain));
        symEncryptReq.setIv(CodecUtils.encodeBase64(iv));
        symEncryptReq.setMode(AlgMode.CBC);

        SymEncryptResp symEncryptResp = execute("/sym/encrypt", symEncryptReq, SymEncryptResp.class);
        Assertions.assertNotNull(symEncryptResp);
        log.info("SymEncryptResp: {}", symEncryptResp);
        Assertions.assertTrue(StringUtils.hasText(symEncryptResp.getKeyIndex()));

        SymDecryptReq decryptReq = new SymDecryptReq();
        decryptReq.setKeyId(keyId);
        decryptReq.setKeyIndex(symEncryptResp.getKeyIndex());
        decryptReq.setIv(CodecUtils.encodeBase64(iv));
        decryptReq.setMode(AlgMode.CBC);
        decryptReq.setCipherData(symEncryptResp.getCipherData());

        SymDecryptResp decryptResp = execute("/sym/decrypt", decryptReq, SymDecryptResp.class);
        Assertions.assertNotNull(decryptResp);
        Assertions.assertNotNull(decryptResp);
        byte[] calPlain = CodecUtils.decodeBase64(decryptResp.getPlainData());
        log.info("SymDecryptResp: {}, {}", calPlain, decryptResp);
        Assertions.assertArrayEquals(plain, calPlain);
    }

    @Test
    public void testHmac() {
        SymHmacReq hmacReq = new SymHmacReq();
        hmacReq.setKeyId(keyId);
        hmacReq.setPlainData(CodecUtils.encodeBase64(plain));
        SymHmacResp hmacResp = execute("/sym/hmac", hmacReq, SymHmacResp.class);
        Assertions.assertNotNull(hmacResp);
        log.info("SymHmacResp: {}", hmacResp);
        byte[] bytes = CodecUtils.decodeBase64(hmacResp.getHmac());
        Assertions.assertEquals(32, bytes.length);

        SymHmacCheckReq checkReq = new SymHmacCheckReq();
        checkReq.setKeyId(keyId);
        checkReq.setKeyIndex(hmacResp.getKeyIndex());
        checkReq.setHmac(hmacResp.getHmac());
        checkReq.setPlainData(CodecUtils.encodeBase64(plain));

        VerifyResp verifyResp = execute("/sym/hmac/check", checkReq, VerifyResp.class);
        Assertions.assertNotNull(verifyResp);
        log.info("VerifyResp: {}", verifyResp);

        Assertions.assertTrue(verifyResp.getVerified());
    }

    @Test
    public void testMac() {
        SymMacReq macReq = new SymMacReq();
        macReq.setKeyId(keyId);
        macReq.setIv(CodecUtils.encodeBase64(iv));
        macReq.setPlainData(CodecUtils.encodeBase64(plain));
        SymMacResp hmacResp = execute("/sym/mac", macReq, SymMacResp.class);
        Assertions.assertNotNull(hmacResp);
        log.info("SymMacResp: {}", hmacResp);
        byte[] bytes = CodecUtils.decodeBase64(hmacResp.getMac());
        Assertions.assertEquals(16, bytes.length);

        SymMacCheckReq checkReq = new SymMacCheckReq();
        checkReq.setKeyId(keyId);
        checkReq.setKeyIndex(hmacResp.getKeyIndex());
        checkReq.setIv(CodecUtils.encodeBase64(iv));
        checkReq.setMac(hmacResp.getMac());
        checkReq.setPlainData(CodecUtils.encodeBase64(plain));

        VerifyResp verifyResp = execute("/sym/mac/check", checkReq, VerifyResp.class);
        Assertions.assertNotNull(verifyResp);
        log.info("VerifyResp: {}", verifyResp);

        Assertions.assertTrue(verifyResp.getVerified());
    }


}
