package cn.gintone.service;

import cn.gintone.ErrorInfo;
import cn.gintone.controller.vo.KeyCodePageReqVO;
import cn.gintone.controller.vo.KeyCodeSaveReqVO;
import cn.gintone.dal.KeyCodeMapper;
import cn.gintone.dto.EncInfo;
import cn.gintone.encryptionUtils.*;
import cn.gintone.entity.KeyCodeDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import cn.iocoder.yudao.framework.common.util.object.BeanUtils;


import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 公钥私钥管理 Service 实现类
 *
 * @author 胡懿
 */
@Service
@Validated
public class KeyCodeServiceImpl implements KeyCodeService {

    @Resource
    private KeyCodeMapper keyCodeMapper;

    @Override
    public Long createKeyCode(KeyCodeSaveReqVO createReqVO) {
        // 插入
        KeyCodeDO keyCode = BeanUtils.toBean(createReqVO, KeyCodeDO.class);
        keyCodeMapper.insert(keyCode);
        // 返回
        return keyCode.getId();
    }

    @Override
    public void updateKeyCode(KeyCodeSaveReqVO updateReqVO) {
        // 校验存在
        validateKeyCodeExists(updateReqVO.getId());
        // 更新
        KeyCodeDO updateObj = BeanUtils.toBean(updateReqVO, KeyCodeDO.class);
        keyCodeMapper.updateById(updateObj);
    }

    @Override
    public void deleteKeyCode(Long id) {
        // 校验存在
        validateKeyCodeExists(id);
        // 删除
        keyCodeMapper.deleteById(id);
    }

    private void validateKeyCodeExists(Long id) {
        if (keyCodeMapper.selectById(id) == null) {
            throw exception(ErrorInfo.KEY_CODE_NOT_EXISTS);
        }
    }

    @Override
    public KeyCodeDO getKeyCode(Long id) {
        return keyCodeMapper.selectById(id);
    }

    @Override
    public PageResult<KeyCodeDO> getKeyCodePage(KeyCodePageReqVO pageReqVO) {
        return keyCodeMapper.selectPage(pageReqVO);
    }

    @Override
    public String initKey() {
        List<KeyCodeDO> keyCodeDOS = keyCodeMapper.selectList(new QueryWrapper<KeyCodeDO>());
        System.out.println("keyCodeDOS:" + keyCodeDOS.size());
        if (null != keyCodeDOS && keyCodeDOS.size() > 0) {
            for (KeyCodeDO keyCodeDO : keyCodeDOS){
                keyCodeMapper.deleteById(keyCodeDO.getId());
            }
        }

        try {
            KeyCodeDO keyCodeDO_rsa = new KeyCodeDO();
            Map<String, String> keyMap = PemFileGenerator.generateAndSaveKeyPair(1024);
            String pubKey_rsa = keyMap.get("publicPem");
            String priKey_rsa = keyMap.get("privatePem");
            keyCodeDO_rsa.setType(1);
            keyCodeDO_rsa.setPublicKey(pubKey_rsa);
            keyCodeDO_rsa.setPrivateKey(priKey_rsa);
            int insert = keyCodeMapper.insert(keyCodeDO_rsa);


            KeyCodeDO keyCodeDo_sm2 = new KeyCodeDO();
            KeyPair keyPair = SM2Util.generateSm2KeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            String pubStr_sm2 = SM2KeyUtils.publicKeyToString(publicKey);
            String priStr_sm2 = SM2KeyUtils.privateKeyToString(privateKey);
            keyCodeDo_sm2.setType(2);
            keyCodeDo_sm2.setPublicKey(pubStr_sm2);
            keyCodeDo_sm2.setPrivateKey(priStr_sm2);
            keyCodeMapper.insert(keyCodeDo_sm2);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return "初始化成功";
    }

    @Override
    public EncInfo rasEncryption(String info) {
        EncInfo encInfo = new EncInfo();
        KeyCodeDO keyCodeDO = keyCodeMapper.selectOne(new QueryWrapper<KeyCodeDO>().eq("type", 1));
        if (null != keyCodeDO) {
            try {
                encInfo.setPrivateKey(keyCodeDO.getPrivateKey());
                PublicKey publicKey = SecureHybridDecryptor.loadPublicKey(keyCodeDO.getPublicKey());
                String encrypt = SecureHybridEncryptor.encrypt(info, publicKey);
                encInfo.setInfo(encrypt);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return encInfo;
    }

    @Override
    public String rasDecrypt(EncInfo encInfo) {
        try {
            PrivateKey privateKey = SecureHybridDecryptor.loadPrivateKey(encInfo.getPrivateKey());
            // 解密
            String decrypted = SecureHybridDecryptor.decrypt(encInfo.getInfo(), privateKey);
            return decrypted;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}