package com.yonge.cooleshow.biz.dal.service.impl;

import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.common.enums.CertificateTypeEnum;
import com.yonge.cooleshow.biz.dal.entity.ContractTemplate;
import com.yonge.cooleshow.biz.dal.entity.SysUserTsign;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.vo.StudentVo;
import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
import com.yonge.cooleshow.common.constant.SysConfigConstant;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.cooleshow.common.enums.ContractTemplateTypeEnum;
import com.yonge.cooleshow.common.enums.SysUserType;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.thirdparty.eseal.ESealPlugin;
import com.yonge.toolset.thirdparty.storage.StoragePluginContext;
import com.yonge.toolset.thirdparty.storage.provider.KS3StoragePlugin;
import com.yonge.toolset.thirdparty.user.realname.RealnameAuthenticationPluginContext;
import com.yonge.toolset.thirdparty.user.realname.provider.LinkfaceRealnameAuthenticationPlugin;
import com.yonge.toolset.utils.date.DateUtil;
import com.yonge.toolset.utils.freemarker.FreemarkerTemplateEngine;
import com.yonge.toolset.utils.pdf.PDFUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class ContractServiceImpl implements ContractService {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserTsignService sysUserTsignService;
    @Autowired
    private ContractTemplateService contractTemplateService;
    @Autowired
    private SysUserContractRecordService contractRecordService;
    @Autowired
    private StudentService studentService;
    @Autowired
    private TeacherService teacherService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private RealnameAuthenticationPluginContext realnameAuthenticationPluginContext;
    @Autowired
    private StoragePluginContext storagePluginContext;
    @Autowired
    private ESealPlugin eSealPlugin;

    @Value("${contract.baseDir:/var/pdf}")
    private String contractBaseDir;

    @Value("${message.debugMode}")
    private boolean debugMode;

    private DateFormat dateFormatOss = new SimpleDateFormat("yyyy/MM/dd");

    private DateFormat dateFormat1 = new SimpleDateFormat("yyMMddHHmmSS");

    private final Logger logger = LoggerFactory.getLogger(ContractService.class);

    @Override
    @Async
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
    public HttpResponseResult<String> transferProduceContract(Long userId, SysUserType userType, ContractTemplateTypeEnum contractType) {
        SysUser user = sysUserService.findUserById(userId);
        if (user == null) {
            logger.error("用户不存在({})", userId);
            return HttpResponseResult.failed("用户不存在");
        }

        if (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCardNo())) {
            logger.error("身份信息缺失({})", userId);
            return HttpResponseResult.failed("身份信息缺失");
        }

        SysUserTsign sysUserTsign = sysUserTsignService.get(userId);
        if (sysUserTsign == null) {
            try {
                sysUserTsign = register(userId, user.getRealName(), user.getIdCardNo(), user.getPhone());
            } catch (Exception e) {
                logger.error("用户电子签章注册失败", e);
                return HttpResponseResult.failed("用户电子签章注册失败");
            }
        }
        Date date = new Date();

        // 合成freemarker
        String srcPdfPath = contractBaseDir + "/product/" + dateFormat1.format(date) + "/" + userId + "_" + LocalDateTime.now().getSecond() + ".pdf";

        File srcFile = new File(srcPdfPath);

        File debtFile = new File(srcFile.getParent());
        if (!debtFile.exists()) {
            debtFile.mkdirs();
        }

        FreemarkerTemplateEngine templateEngine = FreemarkerTemplateEngine.getInstance();
        templateEngine.setClassForTemplateLoading(ContractServiceImpl.class, "/config/contracts/");

        Boolean signflag = contractRecordService.checkContractSign(userId, userType, contractType);
        if (signflag) {
            return HttpResponseResult.failed("用户已经签署协议");
        }

        // 查询最新协议模板
        ContractTemplate tenantContractTemplate = contractTemplateService.queryLatestContractTemplate(contractType);
        if (tenantContractTemplate == null) {
            logger.error("最新协议模板查询失败");
            return HttpResponseResult.failed("最新协议模板查询失败");
        }
        String mainContent = tenantContractTemplate.getContractTemplateContent();

        Map<String, Object> params = new HashMap<>();
        String companyName = sysConfigService.findConfigValue(SysConfigConstant.COMPANY_NAME);
        if (contractType.equals(ContractTemplateTypeEnum.REGISTER)) {
            params.put("contractName", "用户注册协议");
        } else {
            params.put("contractName", "产品与服务协议");
        }
        params.put("companyName", companyName);
        params.put("companySealPicture", sysConfigService.findConfigValue(SysConfigConstant.COMPANY_SEAL_PICTURE));
        params.put("contractMainContent", mainContent);
        params.put("isShowVisualSeal", false);


        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("realName", user.getRealName());
        userInfo.put("phone", user.getPhone());
        userInfo.put("idCardNo", user.getIdCardNo());

        if (SysUserType.STUDENT.equals(userType)) {
            StudentVo detail = studentService.detail(userId);
            userInfo.put("subjectName", detail.getSubjectName());
        } else if (SysUserType.TEACHER.equals(userType)) {
            TeacherVo detail = teacherService.detail(userId);
            userInfo.put("subjectName", detail.getSubjectName());
        }
        params.put("userInfo", userInfo);

        templateEngine.render(params, "latest_contract_template.ftl", srcFile);

        // 生成借款协议PDF
        try {
            PDFUtil.renderToPDFByData(ContractServiceImpl.class.getResource("/").getFile(), FileUtils.readFileToString(srcFile), srcPdfPath, "simsun.ttc");
        } catch (IOException e) {
            logger.error("生成产品协议失败", e);
            return HttpResponseResult.failed("生成产品协议失败");
        }

        String organCode = sysConfigService.findConfigValue(SysConfigConstant.COMPANY_ORGAN_CODE);
        SysUserTsign organTsign = sysUserTsignService.queryByCardNo(organCode);
        if (organTsign == null) {
            //创建企业签章
            organTsign = addTsign(0L, organCode, companyName);
        }

        eSealPlugin.organSign(organTsign.getSealData(), srcPdfPath, srcPdfPath);
        if (sysUserTsign != null && CertificateTypeEnum.IDENTITY.getCode().equals(user.getCertificateType())) {
            eSealPlugin.userSign(sysUserTsign.getAccountId(), sysUserTsign.getSealData(), srcPdfPath, srcPdfPath);
        }

        // 上传到oss
        String dateStrOss = dateFormatOss.format(date);
        dateStrOss = "product/" + dateStrOss + "/" + DateUtil.getHour(date);
        String pdfFilePath = storagePluginContext.uploadFile(KS3StoragePlugin.PLUGIN_NAME, dateStrOss, srcFile);
        FileUtils.deleteQuietly(srcFile);
        return HttpResponseResult.succeed(pdfFilePath);
    }

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public HttpResponseResult<String> queryProductContract(Long userId, SysUserType userType, ContractTemplateTypeEnum contractType) {
        Map<String, Object> result = new HashMap<>();
        result.put("code", "false");

        SysUser user = sysUserService.findUserById(userId);
        if (user == null) {
            return HttpResponseResult.failed("用户不存在");
        }

        Date date = new Date();

        // 合成freemarker
        String srcPdfPath = contractBaseDir + "/product/" + dateFormat1.format(date) + "/" + userId + "_" + LocalDateTime.now().getSecond() + ".pdf";

        File srcFile = new File(srcPdfPath);

        File debtFile = new File(srcFile.getParent());
        if (!debtFile.exists()) {
            debtFile.mkdirs();
        }

        FreemarkerTemplateEngine templateEngine = FreemarkerTemplateEngine.getInstance();
        templateEngine.setClassForTemplateLoading(ContractServiceImpl.class, "/config/contracts/");

        // 查询最新协议模板
        ContractTemplate tenantContractTemplate = contractTemplateService.queryLatestContractTemplate(contractType);
        if (tenantContractTemplate == null) {
            return HttpResponseResult.failed("最新协议模板查询失败");
        }
        String mainContent = tenantContractTemplate.getContractTemplateContent();
        if(StringUtils.isEmpty(mainContent)){
            return HttpResponseResult.failed("没有协议内容");
        }

        Map<String, Object> params = new HashMap<>();
        String companyName = sysConfigService.findConfigValue(SysConfigConstant.COMPANY_NAME);
        if (contractType.equals(ContractTemplateTypeEnum.REGISTER)) {
            params.put("contractName", "用户注册协议");
        } else {
            params.put("contractName", "产品与服务协议");
        }
        params.put("companyName", companyName);
        params.put("companySealPicture", sysConfigService.findConfigValue(SysConfigConstant.COMPANY_SEAL_PICTURE));
        params.put("contractMainContent", mainContent);
        params.put("isShowVisualSeal", true);


        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("realName", user.getRealName());
        userInfo.put("phone", user.getPhone());
        userInfo.put("idCardNo", user.getIdCardNo());

        if (SysUserType.STUDENT.equals(userType)) {
            StudentVo detail = studentService.detail(userId);
            userInfo.put("subjectName", detail.getSubjectName());
        } else if (SysUserType.TEACHER.equals(userType)) {
            TeacherVo detail = teacherService.detail(userId);
            userInfo.put("subjectName", detail.getSubjectName());
        }
        params.put("userInfo", userInfo);
        templateEngine.render(params, "latest_contract_template.ftl", srcFile);

        String html = "";
        try {
            html = FileUtils.readFileToString(srcFile);
        } catch (IOException e) {
            return HttpResponseResult.failed("读取产品协议出错");
        } finally {
            FileUtils.deleteQuietly(srcFile);
        }
        return HttpResponseResult.succeed(html);
    }


    private SysUserTsign register(Long userId, String realName, String idCardNo, String mobileNo) {
        if (StringUtils.isBlank(realName) || StringUtils.isBlank(idCardNo) || StringUtils.isBlank(mobileNo)) {
            return null;
        }

        SysUserTsign sysUserTsign = sysUserTsignService.get(userId);
        if (sysUserTsign == null) {

            String accountId = "";
            String sealData = "";

            SysUser user = sysUserService.findUserById(userId);
            if (user == null) {
                throw new BizException("用户信息查询失败");
            }

            if (CertificateTypeEnum.IDENTITY.getCode().equals(user.getCertificateType())) {
                if (!debugMode) {
                    realnameAuthenticationPluginContext.getRealnameAuthenticationPlugin(LinkfaceRealnameAuthenticationPlugin.getName()).verify(realName, idCardNo);
                }

                accountId = eSealPlugin.createUserAccount(realName, idCardNo, mobileNo);

                if (StringUtils.isBlank(accountId)) {
                    throw new BizException("创建电子存证账户失败");
                }

                sealData = eSealPlugin.createUserSeal(accountId);

                if (StringUtils.isBlank(sealData)) {
                    throw new BizException("创建电子存证印章失败");
                }
            }
            sysUserTsign = new SysUserTsign(userId, accountId, sealData, realName, idCardNo);

            sysUserTsignService.insert(sysUserTsign);
            return sysUserTsign;
        }
        return null;
    }

    private SysUserTsign addTsign(Long userId, String organCode, String orgName) {
        Optional.ofNullable(organCode).orElseThrow(() -> new BizException("营业执照编号不能为空!"));
        Optional.ofNullable(orgName).orElseThrow(() -> new BizException("营业名称不能为空"));

        SysUserTsign orignSysUserTsign = sysUserTsignService.queryByCardNo(organCode);

        if (orignSysUserTsign == null) {

            String accountId = eSealPlugin.createOrganAccount(orgName, organCode);
            if (StringUtils.isBlank(accountId)) {
                throw new BizException("创建企业电子存证账户失败");
            }

            String sealData = eSealPlugin.createOrganSeal(accountId, "", "");
            if (StringUtils.isBlank(sealData)) {
                throw new BizException("创建电子存证印章失败");
            }

            orignSysUserTsign = new SysUserTsign(-userId, accountId, sealData, orgName, organCode);
            sysUserTsignService.insert(orignSysUserTsign);

        } else if (!StringUtils.equals(orignSysUserTsign.getName(), orgName)) {
            if (eSealPlugin.updateOrganAccount(orignSysUserTsign.getAccountId(), orgName, organCode)) {
                orignSysUserTsign.setName(orgName);
                sysUserTsignService.update(orignSysUserTsign);
            }
        }
        return orignSysUserTsign;

    }

}
