package com.njcn.gather.system.reg.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.EncryptionUtil;
import com.njcn.gather.system.cfg.service.ISysTestConfigService;
import com.njcn.gather.system.dictionary.pojo.enums.DictDataEnum;
import com.njcn.gather.system.dictionary.pojo.po.DictData;
import com.njcn.gather.system.dictionary.service.IDictDataService;
import com.njcn.gather.system.pojo.constant.DictConst;
import com.njcn.gather.system.pojo.enums.SystemResponseEnum;
import com.njcn.gather.system.reg.mapper.SysRegResMapper;
import com.njcn.gather.system.reg.pojo.dto.RegInfoData;
import com.njcn.gather.system.reg.pojo.enums.RegStatusEnum;
import com.njcn.gather.system.reg.pojo.param.SysRegResParam;
import com.njcn.gather.system.reg.pojo.po.SysRegRes;
import com.njcn.gather.system.reg.pojo.vo.SysRegResVO;
import com.njcn.gather.system.reg.service.ISysRegResService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Cipher;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

/**
 * @author caozehui
 * @date 2024-11-21
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysRegResServiceImpl extends ServiceImpl<SysRegResMapper, SysRegRes> implements ISysRegResService {

    private final ISysTestConfigService sysTestConfigService;

    /**
     * 固定私钥
     */
    private static final String fixedPrivateKeyStr = "-----BEGIN PRIVATE KEY-----\n" +
            "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTC6MQkjHAIyPQ\n" +
            "12tfSBsmS12OspsmJORW2cf7s+xwe3lJ3nb9KohjAuRBG4jLceAXdZoCuk1+Xt8l\n" +
            "kesXp930DWmb7SBHLa7imGgvIm/9hP7Y48yDJqM2Ia6CFbMCmLYCiU3oDLZ2DuUq\n" +
            "QbE2j9QuTTMiOVHBy4M82XwkEXNfIQez9PB+Osex2X9FesyMoWvsoOcnDD8iWmbP\n" +
            "Ag0syuutt4YkrU8IWC5v2vyTxb+N+F36wqbC8td1wOgUrf2K3kQtTe7xB1b3i5RI\n" +
            "DAsjxPd1a3uzJVjJ7Onla+B4dkFGOSlX/w8/GJQzMgegskKEPRONyXRWCaVpBt9O\n" +
            "6yDjKz7vAgMBAAECggEATnj+vowlnJRUXnSjM5AbrD8MwCEQSHwiPVsIHcLWkTKQ\n" +
            "NFPYeaVFhk9OcRkcYc1rbj2nsQj2BJ2hKpaZzDd6c6NDGBvxSxYk95OE9bW/34wC\n" +
            "uMHnSwLkYB3hBfSslbQTxVipk7WaaMZ8FpzLmIaddkP1Ve3rRPx3xXn2y3CDriRs\n" +
            "WxVKm4+ri8Ncnk0dBqjEBNwgdsvRlxPMAB9t4mTxS6NENriIWgiBGDiMFT3dstkw\n" +
            "tIvxX/gdrLCd9CbV1iZgH+a/CiKIYcSGzPiYfwEi446cPZwfwYo65C1HBS1mMJju\n" +
            "FwLw0r9OQ9LEsO+ar6d7hss4RmHgRR1JdQyBoq/wbQKBgQD1kkE1TfJpFmCpWR/P\n" +
            "wdl88ABnwEZtaKKMS1A+T2+ywEl3y+iUPoouJ+69zG0s7NuwpeJ2c1S0BB+yFRWx\n" +
            "ExGjJ2Z0GbK++f2R38Y3kvj2lGiB4AZ1sentTuatGHWRzwEd913swrKd/fkFBA/I\n" +
            "x38Mmq7wDqkqIxNh20W2jWWd3QKBgQDcAgg39l5zYeNIUdm/PQINd4G1UjCTcgvn\n" +
            "+7AFpuoCYfx9ReXzvLjGDs8VmuoBIg5Y4bWIUhTSQVQIIRE12EXrysawHs7loegp\n" +
            "FTU6cZAjxT72sRhesr12f5s5Hd3zaMB0Y8PUljAG7lvAVNPQDUkAL7+bmYLxWokq\n" +
            "G/FHJooBOwKBgQCidDWVKNKTuI0Lmv0TeL8DCtaJzEYK/OyDeRNFlVFkZBZ2HLvo\n" +
            "zhKlhB9JCiKzVKHlE2hkSdmgGRZKve4SrXW+hEMfzRxVgJXB2dKMUztGDFmyiVxc\n" +
            "oe0J42dw3Txx0AqCI3HMPeTh5fDF47D5dxhSY0YVYu2ABaI920wb/yBZNQKBgGlz\n" +
            "P+Uy3QqIvJuJP8j9wOIbibwS7N1/KF3EsRXEbx09Qfv5aMJujlG//1nnqolofV/0\n" +
            "r0HrtbchQNm0n78jLkBaLOl1ms1N0Sz/0Ud17xR2EjvDnl6lZVJKz2eM/TkR2Ezx\n" +
            "FIfshJCN5sRE5FEwTPEd8cTuy2hLcLsSMY9c1YDJAoGBAMIPLraI8c7h4hOCNE66\n" +
            "Eg2nEOcqCzmIYTS6ARCPYrOC4cx23+uAScbZCq+vBk34KSJyun1OgfvnRmVerpUU\n" +
            "lld8v62FR3FnNwSY/zeySP8ENCzAUluql0yHzgpBwF3NNYihVdYY4Lm3vlUe4fTt\n" +
            "krNC84FOePuC5qaIefZ03oRX\n" +
            "-----END PRIVATE KEY-----";

    private final IDictDataService dictDataService;

    @Override
    public SysRegRes getRegResByType(String type) {
        return this.lambdaQuery().eq(SysRegRes::getType, type).eq(SysRegRes::getState, DataStateEnum.ENABLE.getCode()).one();
    }

    @Override
    @Transactional
    public boolean addRegRes(SysRegResParam sysRegResParam) {
        List<SysRegRes> regResList = new ArrayList<>();

        RegInfoData regInfoData = decodeRegistrationCode(sysRegResParam.getCode());
        if (ObjectUtil.isNotNull(regInfoData)) {
            // 对比Mac地址
            String mac = getMAC();
            if (!mac.equals(regInfoData.getMacAddress())) {
                throw new BusinessException(SystemResponseEnum.MAC_ADDRESS_NOT_MATCH);
            }

            List<String> expireDateList = regInfoData.getExpireDateList();
            for (int i = 0; i < regInfoData.getTypeList().size(); i++) {
                expireDateList.set(i, formatDate(expireDateList.get(i)));
            }
            // 比对到期日期
            String maxExpireDate = expireDateList.stream().max((a, b) -> a.compareTo(b)).get();
            if (LocalDate.parse(maxExpireDate).isBefore(LocalDate.now())) {
                throw new BusinessException(SystemResponseEnum.REGISTRATION_CODE_EXPIRED);
            }

            sysTestConfigService.addTestConfig(regInfoData.getScene());

            for (int i = 0; i < regInfoData.getTypeList().size(); i++) {
                // 忽略过期的
//                if (isExpire(expireDateList.get(i))) {
//                    continue;
//                }

                SysRegRes sysRegRes = new SysRegRes();
                BeanUtil.copyProperties(sysRegResParam, sysRegRes);
                sysRegRes.setState(DataStateEnum.ENABLE.getCode());
                sysRegRes.setCode(sysRegResParam.getCode());
                sysRegRes.setExpireDate(EncryptionUtil.encodeString(1, formatDate(regInfoData.getExpireDateList().get(i))));

                DictData dictData = dictDataService.getDictDataByCode(regInfoData.getTypeList().get(i));
                if (ObjectUtil.isNotNull(dictData)) {
                    sysRegRes.setType(dictData.getId());
                }

                sysRegRes.setRealTime(20);
                sysRegRes.setStatistics(5);
                sysRegRes.setFlicker(1);

                if (regInfoData.getTypeList().get(i).equals(DictDataEnum.CONTRAST.getCode())) {
                    sysRegRes.setWaveRecord(1);
                    sysRegRes.setRealTime(200);
                    sysRegRes.setStatistics(5);
                    sysRegRes.setFlicker(3);
                }

                regResList.add(sysRegRes);
            }
        }

        // 删除原有的所有数据
        this.remove(null);
        return this.saveBatch(regResList);
    }

    @Override
    @Transactional
    public boolean updateRegRes(SysRegResParam.UpdateParam param) {
        SysRegRes sysRegRes = new SysRegRes();
        BeanUtil.copyProperties(param, sysRegRes);
        if (sysRegRes.getWaveRecord() == -1) {
            sysRegRes.setWaveRecord(null);
        }
        return this.updateById(sysRegRes);
    }

    @Override
    public SysRegResVO listRegRes() {
        // todo 需要切面检测是否到期，到期则状态设为0
        SysRegResVO sysRegResVO = new SysRegResVO();
        List<SysRegRes> regResList = this.lambdaQuery().eq(SysRegRes::getState, DataStateEnum.ENABLE.getCode()).list();
        if (ObjectUtil.isNotEmpty(regResList)) {
            sysRegResVO.setCode(regResList.get(0).getCode());
            sysRegResVO.setSimulateStatus(RegStatusEnum.UNREGISTERED.getCode());
            sysRegResVO.setDigitalStatus(RegStatusEnum.UNREGISTERED.getCode());
            sysRegResVO.setContrastStatus(RegStatusEnum.UNREGISTERED.getCode());
            for (SysRegRes regRes : regResList) {
                DictData dictData = dictDataService.getDictDataById(regRes.getType());
                String s = EncryptionUtil.decoderString(1, regRes.getExpireDate());
                boolean expire = isExpire(s);
                if (ObjectUtil.isNotNull(dictData)) {
                    if (dictData.getCode().equals(DictDataEnum.SIMULATE.getCode())) {
                        if (expire) {
                            sysRegResVO.setSimulateStatus(RegStatusEnum.EXPIRED.getCode());
                        } else {
                            sysRegResVO.setSimulateStatus(RegStatusEnum.REGISTERED.getCode());
                        }
                        sysRegResVO.setSimulateExpireDate(s);
                    }
                    if (dictData.getCode().equals(DictDataEnum.DIGITAL.getCode())) {
                        if (expire) {
                            sysRegResVO.setDigitalStatus(RegStatusEnum.EXPIRED.getCode());
                        } else {
                            sysRegResVO.setDigitalStatus(RegStatusEnum.REGISTERED.getCode());
                        }
                        sysRegResVO.setDigitalExpireDate(s);
                    }
                    if (dictData.getCode().equals(DictDataEnum.CONTRAST.getCode())) {
                        if (expire) {
                            sysRegResVO.setContrastStatus(RegStatusEnum.EXPIRED.getCode());
                        } else {
                            sysRegResVO.setContrastStatus(RegStatusEnum.REGISTERED.getCode());
                        }
                        sysRegResVO.setContrastExpireDate(s);
                    }
                } else {
                    throw new BusinessException("字典数据缺失，请联系管理员！");
                }
            }
        }
        return sysRegResVO;
    }

    @Override
    public SysRegRes getContrastRegRes() {
        return this.getRegResByType(DictConst.REG_RES_CONTRAST_ID);
    }

    /**
     * 格式化日期 (将日期格式化为yyyy-MM-dd)
     *
     * @param date
     * @return
     */
    private String formatDate(String date) {
        String[] split = date.split("-");
        if (split[1].length() == 1) {
            split[1] = "0" + split[1];
        }
        if (split[2].length() == 1) {
            split[2] = "0" + split[2];
        }
        return split[0] + "-" + split[1] + "-" + split[2];
    }

    /**
     * 判断是否到期
     *
     * @param expireDate 到期日期
     * @return
     */
    private boolean isExpire(String expireDate) {
        expireDate = formatDate(expireDate);
        String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        if (today.compareTo(expireDate) >= 0) {
            return true;
        }
        return false;
    }

    /**
     * 使用hutool工具获取本机mac地址
     *
     * @return mac地址
     */
    private String getMAC() {
        InetAddress inetAddress = null;
        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            throw new BusinessException(SystemResponseEnum.GET_MAC_ADDRESS_FAILED);
        }
        return NetUtil.getMacAddress(inetAddress);
    }

    /**
     * 解析 PEM 格式的密钥
     *
     * @param pem PEM 格式的密钥
     * @return 密钥对象
     * @throws Exception
     */
    private Key parsePemKey(String pem) throws Exception {
        // 去掉 PEM 格式中的头部和尾部
        String cleanPem = pem
                .replaceAll("-----BEGIN (.*?)-----", "")
                .replaceAll("-----END (.*?)-----", "")
                .replaceAll("\\s+", ""); // 移除换行和空格

        byte[] decodedKey = Base64.getDecoder().decode(cleanPem);

        // 根据密钥类型导入密钥
        if (pem.contains("PRIVATE")) {
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            return privateKey;
        } else {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return publicKey;
        }
    }

    /**
     * 解析注册码
     *
     * @param encryptedCode 加密后的注册码
     * @return
     */
    private RegInfoData decodeRegistrationCode(String encryptedCode) {
        try {
            byte[] encryptedData = Base64.getDecoder().decode(encryptedCode);
            Key privateKey = parsePemKey(fixedPrivateKeyStr);

            // 使用 RSA/OAEP 解密
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] decryptedData = cipher.doFinal(encryptedData);

            // 将解密后的字节数组转换为字符串
            String decodedString = new String(decryptedData, StandardCharsets.UTF_8);

            ObjectMapper objectMapper = new ObjectMapper();
            RegInfoData regInfoData = objectMapper.readValue(decodedString, RegInfoData.class);
            if (ObjectUtil.isNull(regInfoData) || ObjectUtil.isNull(regInfoData.getScene()) || regInfoData.getTypeList().size() == 0 || regInfoData.getTypeList().size() != regInfoData.getExpireDateList().size()) {
                throw new BusinessException(SystemResponseEnum.REGISTRATION_CODE_FORMAT_ERROR);
            }
            return regInfoData;
        } catch (Exception e) {
            throw new BusinessException(SystemResponseEnum.REGISTRATION_CODE_FORMAT_ERROR);
        }
    }
}
