package com.chinaweal.aiccs.aiccs.fraudreg.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.chinaweal.aiccs.aiccs.abnormal.entity.EBaseinfo;
import com.chinaweal.aiccs.aiccs.abnormal.entity.Gzaiccode;
import com.chinaweal.aiccs.aiccs.abnormal.entity.TSAttachment;
import com.chinaweal.aiccs.aiccs.abnormal.service.EBaseinfoService;
import com.chinaweal.aiccs.aiccs.abnormal.service.IGzaiccodeService;
import com.chinaweal.aiccs.aiccs.abnormal.service.TSAttachmentService;
import com.chinaweal.aiccs.aiccs.asyncTask.RevokeAsyncTask;
import com.chinaweal.aiccs.aiccs.business.entity.TSTaskList;
import com.chinaweal.aiccs.aiccs.business.entity.TSTwfProcessNode;
import com.chinaweal.aiccs.aiccs.business.service.TSTaskListService;
import com.chinaweal.aiccs.aiccs.business.service.WorkFlowService;
import com.chinaweal.aiccs.aiccs.fraudreg.dto.FraudInfoDto;
import com.chinaweal.aiccs.aiccs.fraudreg.dto.FraudProcessDto;
import com.chinaweal.aiccs.aiccs.fraudreg.entity.TBizFraud;
import com.chinaweal.aiccs.aiccs.fraudreg.entity.TFraudCheck;
import com.chinaweal.aiccs.aiccs.fraudreg.entity.TFraudEnt;
import com.chinaweal.aiccs.aiccs.fraudreg.entity.TFraudPerson;
import com.chinaweal.aiccs.aiccs.fraudreg.service.*;
import com.chinaweal.aiccs.aiccs.market.service.ITSUsualInspectService;
import com.chinaweal.aiccs.aiccs.revoke.entity.CancelRegisterList;
import com.chinaweal.aiccs.aiccs.revoke.entity.CancelRevokelist;
import com.chinaweal.aiccs.aiccs.temp.service.TemporarySaveService;
import com.chinaweal.aiccs.common.constant.BaseDataConstant;
import com.chinaweal.aiccs.common.constant.Constant;
import com.chinaweal.aiccs.common.util.FlowUtil;
import com.chinaweal.aiccs.common.util.HandleWorkFlowUtil;
import com.chinaweal.aiccs.common.util.StringUtils;
import com.chinaweal.aiccs.common.util.filestorage.FileStorageService;
import com.chinaweal.aiccs.config.CommonConfig;
import com.chinaweal.aiccs.org.service.TUsersService;
import com.chinaweal.aicorg.model.AICUser;
import com.chinaweal.aicorg.services.OrgUM;
import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import com.chinaweal.youfool.framework.springboot.rest.ResultCode;
import com.chinaweal.youfool.framework.sso.util.SSOUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * Created by IDEA.
 * Code: Yangmc
 * Date: 2021/11/12
 * Time: 13:50
 */

@Service
@Slf4j
public class FraudProcessServiceImpl implements IFraudProcessService {

    @Resource
    private FileStorageService fileStorageService;

    @Resource
    private ITBizFraudService itBizFraudService;
    @Resource
    private ITFraudEntService itFraudEntService;
    @Resource
    private ITFraudPersonService itFraudPersonService;
    @Resource
    private EBaseinfoService eBaseInfoService;
    @Resource
    private TSTaskListService taskListService;
    @Resource
    private WorkFlowService workFlowService;
    @Resource
    private TSAttachmentService attachmentService;
    @Resource
    private OrgUM orgUM;
    @Resource
    private ITSUsualInspectService iTSUsualInspectService;
    @Resource
    private ITFraudCheckService iTFraudCheckService;
    @Resource
    private TUsersService tUsersService;
    @Resource
    private IGzaiccodeService iGzaiccodeService;
    @Resource
    private TemporarySaveService temporarySaveService;
    @Resource
    private RevokeAsyncTask revokeAsyncTask;

    @Override
    public Map<String, String> startTask(FraudInfoDto fraudInfoDto, AICUser loginUser) {

        Map<String, String> resultMap = new HashMap<>();
        EBaseinfo eBaseInfo = eBaseInfoService.getEntBaseInfoByCode(fraudInfoDto.getUniScId());

        String bizSeq = IdUtil.simpleUUID();

        // 冒用业务信息
        TBizFraud tBizFraud = new TBizFraud();
        BeanUtils.copyProperties(fraudInfoDto, tBizFraud);
        tBizFraud.setBizSeq(bizSeq);
        tBizFraud.setUserId(loginUser.getPrimaryKey());
        tBizFraud.setOrgUnitID(loginUser.getRegionID());
        tBizFraud.setIntoSponsor(loginUser.getName());
        tBizFraud.setStatus("1");
        tBizFraud.setLinkType("1");
        itBizFraudService.save(tBizFraud);

        // 涉嫌冒用企业主体信息
        TFraudEnt tFraudEnt = new TFraudEnt();
        tFraudEnt.setBizSeq(bizSeq);
        tFraudEnt.setPripid(eBaseInfo.getPripid());
        tFraudEnt.setName(fraudInfoDto.getComplainerName());
        tFraudEnt.setEntName(eBaseInfo.getEntname());
        tFraudEnt.setUniScId(eBaseInfo.getUniscid());
        tFraudEnt.setRegNo(eBaseInfo.getRegno());
        tFraudEnt.setRegOrg(eBaseInfo.getRegorg());
        tFraudEnt.setRegOrgCn(eBaseInfo.getRegorgCn());
        tFraudEnt.setTel(eBaseInfo.getTel());
        tFraudEnt.setRegTime(eBaseInfo.getEstdate());
        itFraudEntService.save(tFraudEnt);

        // 虚假责任人
        TFraudPerson tFraudPerson = new TFraudPerson();
        tFraudPerson.setBizSeq(bizSeq);
        tFraudPerson.setPripid(eBaseInfo.getPripid());
        tFraudPerson.setName(eBaseInfo.getName());
        tFraudPerson.setEntName(eBaseInfo.getEntname());
        tFraudPerson.setUniScId(eBaseInfo.getUniscid());
        tFraudPerson.setRegNo(eBaseInfo.getRegno());
        itFraudPersonService.save(tFraudPerson);

        // 启动工作流
        TSTaskList tsTaskList = new TSTaskList();
        tsTaskList.setBizseqid(bizSeq);
        if("1".equals(tBizFraud.getBusinessType())){
            tsTaskList.setBustype(BaseDataConstant.CANCEL_REGISTRATION);
        }else if ("2".equals(tBizFraud.getBusinessType())) {
            tsTaskList.setBustype(BaseDataConstant.CANCEL_REGISTRATIONBG);
        }else if ("3".equals(tBizFraud.getBusinessType())){
            tsTaskList.setBustype(BaseDataConstant.CANCEL_REGISTRATIONZX);
        }else {
            tsTaskList.setBustype(BaseDataConstant.CANCEL_REGISTRATION);
        }

        tsTaskList.setBusname(eBaseInfo.getEntname());
        //新待办 设置待办信息
        tsTaskList = HandleWorkFlowUtil.createTaskList(tsTaskList, loginUser);
        //开始工作流
        taskListService.startWorkFlow(tsTaskList, loginUser, FlowUtil.CANCELWORKFLOW);

        // 返回结果
        resultMap.put("taskId", tsTaskList.getTasklistid());
        resultMap.put("bizSeq", bizSeq);
        resultMap.put("workflowId", tsTaskList.getWorkflowid());
        resultMap.put("pripid", eBaseInfo.getPripid());
        return resultMap;
    }

    @Override
    public void backStartAccept(FraudProcessDto fraudProcessDto, TSTaskList tsTaskList, AICUser loginUser) {

        TBizFraud tBizFraud = itBizFraudService.getTBizFraudByBizSeq(fraudProcessDto.getBizSeq());
        tBizFraud.setStatus("1");
        tBizFraud.setLinkType("1");
        itBizFraudService.updateById(tBizFraud);

        // 获取受理环节经办人
        AICUser acceptUser = orgUM.findUserByPrimaryKey(tBizFraud.getUserId());
        fraudProcessDto.setNextPerformerIds(new String[]{acceptUser.getPrimaryKey()});
        fraudProcessDto.setNextPerformerNames(new String[]{acceptUser.getName()});

        // 流程推进
        taskListService.updateWorkFlow(loginUser, fraudProcessDto.getOpinion(), tsTaskList,
                fraudProcessDto.getNextNodeID(), fraudProcessDto.getNextPerformerIds(), fraudProcessDto.getNextPerformerNames());

    }

    @Override
    public void toApprovalCancel(FraudProcessDto fraudProcessDto, TSTaskList tsTaskList, AICUser loginUser) {

        TFraudEnt tFraudEnt = itFraudEntService.getByBizSeq(fraudProcessDto.getBizSeq());
        BeanUtil.copyProperties(fraudProcessDto.getFraudEntInfo(), tFraudEnt);
        itFraudEntService.updateById(tFraudEnt);

        saveFraudPerson(fraudProcessDto);

        TBizFraud tBizFraud = itBizFraudService.getTBizFraudByBizSeq(fraudProcessDto.getBizSeq());
        tBizFraud.setLinkType("3");
        tBizFraud.setComplaintReason(fraudProcessDto.getComplaintReason());
        itBizFraudService.updateById(tBizFraud);

        // 流程推进
        taskListService.updateWorkFlow(loginUser, fraudProcessDto.getOpinion(), tsTaskList,
                fraudProcessDto.getNextNodeID(), fraudProcessDto.getNextPerformerIds(), fraudProcessDto.getNextPerformerNames());
    }

    @Override
    public void toHandleCase(FraudProcessDto fraudProcessDto, TSTaskList tsTaskList, AICUser loginUser) {

        // 增加公示日期
        TFraudEnt tFraudEnt = itFraudEntService.getByBizSeq(fraudProcessDto.getBizSeq());
        BeanUtil.copyProperties(fraudProcessDto.getFraudEntInfo(), tFraudEnt);
        tFraudEnt.setNoticeFrom(LocalDate.now());
        tFraudEnt.setNoticeTo(LocalDate.now().plusDays(45));
        itFraudEntService.updateById(tFraudEnt);

        saveFraudPerson(fraudProcessDto);

        TBizFraud tBizFraud = itBizFraudService.getTBizFraudByBizSeq(fraudProcessDto.getBizSeq());
        tBizFraud.setLinkType("4");
        tBizFraud.setComplaintReason(fraudProcessDto.getComplaintReason());
        itBizFraudService.updateById(tBizFraud);


        // 获取受理环节经办人
        AICUser acceptUser = orgUM.findUserByPrimaryKey(tBizFraud.getUserId());
        fraudProcessDto.setNextPerformerIds(new String[]{acceptUser.getPrimaryKey()});
        fraudProcessDto.setNextPerformerNames(new String[]{acceptUser.getName()});

        // 流程推进
        taskListService.updateWorkFlow(loginUser, fraudProcessDto.getOpinion(), tsTaskList,
                fraudProcessDto.getNextNodeID(), fraudProcessDto.getNextPerformerIds(), fraudProcessDto.getNextPerformerNames());
    }

    @Override
    public String toEndCase(FraudProcessDto fraudProcessDto, TSTaskList tsTaskList, AICUser loginUser) {
        TBizFraud tBizFraud = itBizFraudService.getTBizFraudByBizSeq(fraudProcessDto.getBizSeq());      // 获取涉嫌冒用登记业务表信息
        if(fraudProcessDto.getBizHandleResult().equals("撤销设立")){
            //设置撤销设立结果表相关信息
            AICUser aicUser = SSOUtil.getUser();
            CancelRegisterList cancelRegister = new CancelRegisterList();
            cancelRegister.setBizFraudId(tBizFraud.getId())
                    .setPripid(fraudProcessDto.getFraudEntInfo().getPripid())
                    .setUniscid(fraudProcessDto.getFraudEntInfo().getUniScId())
                    .setEntname(fraudProcessDto.getFraudEntInfo().getEntName())
                    .setRegno(fraudProcessDto.getFraudEntInfo().getRegNo())
                    .setCanceldocno(fraudProcessDto.getFraudEntInfo().getCanceldocno())
                    .setCancelregtype("2")      // 撤销登记类型默认是2
                    .setCancelrea("4")          // 撤销原因默认是4
                    .setAutoaddresslock(fraudProcessDto.getFraudEntInfo().getAutoaddresslock())
                    .setUsername("信用监管系统")
                    .setHandlerid(aicUser.getPrimaryKey())
                    .setHandlername(aicUser.getName())
                    .setHandledecorg(fraudProcessDto.getFraudEntInfo().getJudAuth());

            //调用泰富撤销设立接口
            String result = revokeAsyncTask.tfRevocationReg(cancelRegister);
            if(!"success".equals(result)){      //接口调用失败
                String errorMsg = getCancelRegisterExcode(result);
                return errorMsg;
            }
        }
        tBizFraud.setBizHandleResult(fraudProcessDto.getBizHandleResult());
        tBizFraud.setStatus("3");
        tBizFraud.setLinkType("4");
        itBizFraudService.updateById(tBizFraud);
        TFraudEnt tFraudEnt = itFraudEntService.getByBizSeq(fraudProcessDto.getBizSeq());
        BeanUtil.copyProperties(fraudProcessDto.getFraudEntInfo(), tFraudEnt);
        itFraudEntService.updateById(tFraudEnt);

        // 当投诉原因是“冒用他人信息登记”, 处理原因是101、102、103、199四类原因时，需要同步公示虚假登记责任人信息
        if ("冒用他人身份信息登记".equals(fraudProcessDto.getComplaintReason()) && StringUtils.containsAny(tFraudEnt.getHandleRea(), "101", "102", "103", "199")) {
            TFraudPerson tFraudPerson = itFraudPersonService.getByBizSeq(fraudProcessDto.getBizSeq());
            BeanUtil.copyProperties(fraudProcessDto.getFraudPersonInfo(), tFraudPerson);
            tFraudPerson.setHandleRea(tFraudEnt.getHandleRea());
            tFraudPerson.setHandleResult(tFraudEnt.getHandleResult());
            tFraudPerson.setJudAuth(tFraudEnt.getJudAuth());
            tFraudPerson.setJudauthCn(tFraudEnt.getJudAuthCn());
            tFraudPerson.setJudDate(tFraudEnt.getJudDate());
            itFraudPersonService.updateById(tFraudPerson);
        }

        // 流程推进
        taskListService.updateWorkFlow(loginUser, fraudProcessDto.getOpinion(), tsTaskList,
                fraudProcessDto.getNextNodeID(), fraudProcessDto.getNextPerformerIds(), fraudProcessDto.getNextPerformerNames());

        return "success";
    }

    @Override
    public void toHandleCancel(FraudProcessDto fraudProcessDto, TSTaskList tsTaskList, AICUser loginUser) {

        TFraudEnt tFraudEnt = itFraudEntService.getByBizSeq(fraudProcessDto.getBizSeq());
        BeanUtil.copyProperties(fraudProcessDto.getFraudEntInfo(), tFraudEnt);
        itFraudEntService.updateById(tFraudEnt);

        saveFraudPerson(fraudProcessDto);

        TBizFraud tBizFraud = itBizFraudService.getTBizFraudByBizSeq(fraudProcessDto.getBizSeq());
        tBizFraud.setLinkType("2");
        tBizFraud.setStatus("2");
        tBizFraud.setComplaintReason(fraudProcessDto.getComplaintReason());
        tBizFraud.setIsCase(fraudProcessDto.getIsCase());
        itBizFraudService.updateById(tBizFraud);

        // 是否转现场核查 1-发起
        if ("1".equals(fraudProcessDto.getIsCase())) {

            Optional<TFraudCheck> optional = iTFraudCheckService.lambdaQuery().eq(TFraudCheck::getBizSeq, fraudProcessDto.getBizSeq()).oneOpt();

            if (!optional.isPresent()) {

                // 生成转现场核查业务
                EBaseinfo eBaseInfo = eBaseInfoService.lambdaQuery().eq(EBaseinfo::getUniscid, tFraudEnt.getUniScId()).one();
                Gzaiccode gzaiccode = tUsersService.findOrganization(loginUser.getPrimaryKey());

                TFraudCheck tFraudCheck = fraudProcessDto.getFraudCheckInfo();
                tFraudCheck.setBizSeq(fraudProcessDto.getBizSeq());
                tFraudCheck.setPripid(eBaseInfo.getPripid());
                tFraudCheck.setEntName(eBaseInfo.getEntname());
                tFraudCheck.setUscc(eBaseInfo.getUniscid());
                tFraudCheck.setDomdistrict(StringUtils.isBlank(eBaseInfo.getDomdistrict())? eBaseInfo.getRegorg() : eBaseInfo.getDomdistrict());
                tFraudCheck.setSupOrg(eBaseInfo.getSuporg());
                tFraudCheck.setSupOrgCn(iGzaiccodeService.getNameByCode(eBaseInfo.getSuporg()));

                // 非市局发起并且属地监管不为空，直接分派当监管所
                if (StringUtils.isNotBlank(eBaseInfo.getSuporg()) && !"440101".equals(loginUser.getRegionID())) {
                    tFraudCheck.setStatus("1");
                    tFraudCheck.setSendOrg(eBaseInfo.getSuporg());
                } else {
                    tFraudCheck.setStatus("0");

                    if ("440101".equals(tFraudCheck.getDomdistrict())) {
                        if (StringUtils.isNotBlank(eBaseInfo.getSuporg())) {
                            tFraudCheck.setDomdistrict(eBaseInfo.getSuporg().substring(0, 6));
                        } else {
                            throw new BusinessException(ResultCode.BUSINESS_LOGIC_ERROR, "数据出错，无法发起现场核查业务。");
                        }
                    }
                }

                tFraudCheck.setOrg(gzaiccode.getScountrycode());
                tFraudCheck.setOrgCn(gzaiccode.getSregorgname());
                tFraudCheck.setUserId(loginUser.getPrimaryKey());
                tFraudCheck.setUserName(loginUser.getName());
                tFraudCheck.setHandleTime(LocalDateTime.now());
                iTFraudCheckService.save(tFraudCheck);
            }
        }

        // 流程推进
        taskListService.updateWorkFlow(loginUser, fraudProcessDto.getOpinion(), tsTaskList,
                fraudProcessDto.getNextNodeID(), fraudProcessDto.getNextPerformerIds(), fraudProcessDto.getNextPerformerNames());
    }

    @Override
    public void cancelCase(FraudProcessDto fraudProcessDto, TSTaskList tsTaskList, AICUser loginUser) {
//        tsTaskList.setBusstatus("2");
//        taskListService.updateById(tsTaskList);

        TBizFraud tBizFraud = itBizFraudService.getTBizFraudByBizSeq(fraudProcessDto.getBizSeq());
        tBizFraud.setStatus("4");
        itBizFraudService.updateById(tBizFraud);
        // 流程推进
        taskListService.updateWorkFlow(loginUser, fraudProcessDto.getOpinion(), tsTaskList,
                fraudProcessDto.getNextNodeID(), new String[]{loginUser.getPrimaryKey()}, new String[]{loginUser.getName()});

    }

    @Override
    public String processControl(FraudProcessDto fraudProcessDto, TSTaskList taskList, AICUser loginUser) {
        TSTwfProcessNode twfProcessNode = workFlowService.findCurrentNode(taskList.getWorkflowid());
        String link = String.format("%s_%s", twfProcessNode.getCurrentnode(), fraudProcessDto.getNextNodeID());
        String msg="success";
        // 参考 cancelWorkFlow.xml 配置流程扭转
        switch (link) {
            case "startAccept_handleCancel":
                this.toHandleCancel(fraudProcessDto, taskList, loginUser);
                break;
            case "handleCase_cancelCase":
            case "startAccept_cancelCase":
                this.cancelCase(fraudProcessDto, taskList, loginUser);
                break;
            case "handleCancel_startAccept":
            case "approvalCancel_startAccept":
                this.backStartAccept(fraudProcessDto, taskList, loginUser);
                break;
            case "handleCancel_approvalCancel":
                this.toApprovalCancel(fraudProcessDto, taskList, loginUser);
                break;
            case "approvalCancel_handleCase":
                this.toHandleCase(fraudProcessDto, taskList, loginUser);
                break;
            case "handleCase_endCase":
                msg=this.toEndCase(fraudProcessDto, taskList, loginUser);
                if(!msg.equals("success")) return msg;
                break;
            default:
                throw new RuntimeException("流程扭转出错");
        }
        temporarySaveService.delByBizseq(fraudProcessDto.getBizSeq());
        return msg;
    }

    @Override
    public List<TSAttachment> upload(MultipartFile[] files, String id, String attachType,  AICUser loginUser) throws IOException {

        List<TSAttachment> list = new ArrayList<>();

        // 获得上传目录
        String realPath = CommonConfig.getFraudRegPath();
        realPath +=  File.separator + id;

        for (MultipartFile file : files) {
            String fileName = file.getOriginalFilename();
            String ext = StringUtils.isNotBlank(fileName) && fileName.lastIndexOf(Constant.DOT) > -1 ? fileName.substring(fileName.lastIndexOf(Constant.DOT)) : StringUtils.EMPTY;

            String virtualFileName = IdUtil.simpleUUID() + ext;

            fileStorageService.writeFromStream(realPath, virtualFileName, file.getInputStream());

            TSAttachment tsAttachment = new TSAttachment();
            tsAttachment.setBizseq(id);
            tsAttachment.setPripid(StringUtils.EMPTY);
            tsAttachment.setFileext(ext);
            tsAttachment.setFilename(fileName);
            tsAttachment.setFileurl(realPath + File.separator + virtualFileName);
            tsAttachment.setUploaddate(LocalDate.now());
            tsAttachment.setUserid(loginUser.getPrimaryKey());
            tsAttachment.setUsername(loginUser.getName());
            tsAttachment.setAttachtype(attachType); // 1-线索来源 2-上传附件
            attachmentService.save(tsAttachment);

            list.add(tsAttachment);
        }
        return list;
    }

    /**
     * 保存虚假责任人信息
     * @param fraudProcessDto
     */
    private void saveFraudPerson(FraudProcessDto fraudProcessDto) {
        TFraudPerson tFraudPerson = itFraudPersonService.getByBizSeq(fraudProcessDto.getBizSeq());
        BeanUtil.copyProperties(fraudProcessDto.getFraudPersonInfo(), tFraudPerson);
        itFraudPersonService.updateById(tFraudPerson);
    }

    //根据异常代码显示对应的提示语
    private String getCancelRegisterExcode(String excode){
        String msg = "";
        switch (excode){
            case "001":
                msg = "未找到对应的主体，请核实该主体是否真实存在。";
                break;
            case "002":
                msg = "该主体不允许撤销设立，请核查是否已经撤销设立或已注销或迁出中。";
                break;
            case "003":
                msg="该主体存在锁定信息，不允许撤销设立，请先到注册系统进行解锁操作。";
                break;
            default:
                msg = "撤销设立失败，请联系系统工程师进一步排查原因。";
                break;
        }
        return msg;
    }
}
