package com.yeejoin.amos.boot.module.tzs.flc.biz.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.workflow.feign.WorkflowFeignService;
import com.yeejoin.amos.boot.module.common.api.dto.AttachmentDto;
import com.yeejoin.amos.boot.module.common.api.dto.FailureDetailsDto;
import com.yeejoin.amos.boot.module.common.api.entity.OrgUsr;
import com.yeejoin.amos.boot.module.common.api.enums.FailureStatuEnum;
import com.yeejoin.amos.boot.module.common.biz.service.impl.OrgUsrServiceImpl;
import com.yeejoin.amos.boot.module.common.biz.service.impl.SourceFileServiceImpl;
import com.yeejoin.amos.boot.module.tzs.api.dto.AlertCalledQueryDto;
import com.yeejoin.amos.boot.module.tzs.api.enums.InformWorkFlowEnum;
import com.yeejoin.amos.boot.module.tzs.flc.api.dto.EquipmentDto;
import com.yeejoin.amos.boot.module.tzs.flc.api.dto.EquipmentIndexDto;
import com.yeejoin.amos.boot.module.tzs.flc.api.dto.InformEquipmentDto;
import com.yeejoin.amos.boot.module.tzs.flc.api.entity.Equipment;
import com.yeejoin.amos.boot.module.tzs.flc.api.entity.EquipmentIndex;
import com.yeejoin.amos.boot.module.tzs.flc.api.entity.EquipmentIndexInform;
import com.yeejoin.amos.boot.module.tzs.flc.api.entity.EquipmentInform;
import com.yeejoin.amos.boot.module.tzs.flc.api.enums.EquipmentInformStatusEnum;
import com.yeejoin.amos.boot.module.tzs.flc.api.enums.EquipmentStatusEnum;
import com.yeejoin.amos.boot.module.tzs.flc.api.mapper.EquipmentInformMapper;
import com.yeejoin.amos.boot.module.tzs.flc.api.service.IEquipmentIndexInformService;
import com.yeejoin.amos.boot.module.tzs.flc.api.service.IEquipmentInformService;
import com.yeejoin.amos.boot.module.tzs.flc.api.dto.EquipmentInformDto;
import com.yeejoin.amos.boot.module.tzs.flc.api.service.IInformEquipmentService;
import com.yeejoin.amos.boot.module.tzs.flc.api.service.IInformProcessInfoService;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * 设备告知单服务实现类
 *
 * @author system_generator
 * @date 2021-12-10
 */
@Service
public class EquipmentInformServiceImpl extends BaseService<EquipmentInformDto,EquipmentInform,EquipmentInformMapper> implements IEquipmentInformService {

    @Autowired
    SourceFileServiceImpl sourceFileService;

    @Autowired
    WorkflowFeignService workflowFeignService;


    @Autowired
    EquipmentServiceImpl equipmentServiceImpl;

    @Autowired
    OrgUsrServiceImpl iOrgUsrService;

    @Autowired
    EquipmentIndexServiceImpl equipmentIndexServiceImpl;

    @Autowired
    InformEquipmentServiceImpl informEquipmentServiceImpl;

    @Value("${inform.work.flow.processDefinitionKey}")
    private String processDefinitionKey;

    @Autowired
    IInformProcessInfoService iInformProcessInfoService;

    @Autowired
    EquipmentIndexInformServiceImpl iEquipmentIndexInformService;



    /**
     * 分页查询
     */
    public Page<EquipmentInformDto> queryForEquipmentInformPage(Page<EquipmentInformDto> page)   {
        return this.queryForPage(page, null, false);
    }

    /**
     * 列表查询 示例
     */
    public List<EquipmentInformDto> queryForEquipmentInformList()   {
        return this.queryForList("" , false);
    }

    @Override
    public EquipmentInformDto createEquipmentInform(EquipmentInformDto model, ReginParams userInfo) {
        model.setInformStatus(EquipmentInformStatusEnum.暂存.getCode());
        if(model.getSequenceNbr() == null) { // 新增
            // 获取用户所在单位 保存施工单位所属信息
            OrgUsr myUnit = null;
            AgencyUserModel user = Privilege.agencyUserClient.getme().getResult();
            List<CompanyModel> companys = user.getCompanys();
            for(CompanyModel c : companys) {
                myUnit = iOrgUsrService.getOne(new LambdaQueryWrapper<OrgUsr>().eq(OrgUsr::getIsDelete,false).eq(OrgUsr::getAmosOrgId,c.getSequenceNbr()));
            }
            if(myUnit == null) {
                throw  new BadRequest("该用户非施工单位人员无法创建告知单");
            }
            model.setProductInformDate(new Date());
            model.setProductUnitId(myUnit.getSequenceNbr());
            model.setProductUnit(myUnit.getBizOrgName());
            model = this.createWithModel(model);
        } else {
            model = this.updateWithModel(model);
        }
        saveSourceFile(model);
        return model;
    }

    @Override
    public Page<EquipmentInformDto> queryDtoList(Page<EquipmentInformDto> page, EquipmentInformDto equipmentInformDto, String sortParam, String sortRule) {
        AgencyUserModel user = Privilege.agencyUserClient.getme().getResult();
        List<CompanyModel> companys = user.getCompanys();
        Long cpmpanyId = -1l;
        for(CompanyModel c : companys) {
            cpmpanyId = iOrgUsrService.getOne(new LambdaQueryWrapper<OrgUsr>().eq(OrgUsr::getIsDelete,false).eq(OrgUsr::getAmosOrgId,c.getSequenceNbr())).getSequenceNbr();
        }
        if(cpmpanyId == -1l) {
            throw new BadRequest("未找到登陆人所在企业");
        }

        Page<List<EquipmentInformDto>>list = baseMapper.queryDtoList(page,equipmentInformDto.getProductCode(),equipmentInformDto.getProductInformDateStart(),equipmentInformDto.getProductInformDateEnd(),
                equipmentInformDto.getProductUnitId(),equipmentInformDto.getRegionCode(),equipmentInformDto.getAddress(),equipmentInformDto.getPlanProductDateStart(),equipmentInformDto.getPlanProductDateEnd(),
                equipmentInformDto.getAcceptUnitId(),equipmentInformDto.getInformStatus(),sortParam,sortRule,cpmpanyId);
        Page<EquipmentInformDto> page1 = new Page<>();
        List<EquipmentInformDto> resultDtoList = JSONArray.parseArray(JSONArray.toJSONString(list.getRecords()),EquipmentInformDto.class);
        page1.setCurrent(page.getCurrent());
        page1.setSize(page.getSize());
        page1.setTotal(list.getTotal());
        page1.setRecords(resultDtoList);
        return page1;
    }

    @Override
    public Page<EquipmentInformDto> queryDtoListSub(Page<EquipmentInformDto> page, EquipmentInformDto equipmentInformDto, String sortParam, String sortRule) {
        AgencyUserModel user = Privilege.agencyUserClient.getme().getResult();
        List<CompanyModel> companys = user.getCompanys();
        Long cpmpanyId = -1l;
        for(CompanyModel c : companys) {
            cpmpanyId = c.getSequenceNbr();
        }
        if(cpmpanyId == -1l) {
            throw new BadRequest("未找到登陆人所在企业");
        }
        Page<List<EquipmentInformDto>>list = baseMapper.queryDtoListSub(page,equipmentInformDto.getProductCode(),equipmentInformDto.getProductInformDateStart(),equipmentInformDto.getProductInformDateEnd(),
                equipmentInformDto.getProductUnitId(),equipmentInformDto.getRegionCode(),equipmentInformDto.getAddress(),equipmentInformDto.getPlanProductDateStart(),equipmentInformDto.getPlanProductDateEnd(),
                equipmentInformDto.getAcceptUnitId(),equipmentInformDto.getInformStatus(),sortParam,sortRule,cpmpanyId);
        Page<EquipmentInformDto> page1 = new Page<>();
        List<EquipmentInformDto> resultDtoList = JSONArray.parseArray(JSONArray.toJSONString(list.getRecords()),EquipmentInformDto.class);
        page1.setCurrent(page.getCurrent());
        page1.setSize(page.getSize());
        page1.setTotal(list.getTotal());
        page1.setRecords(resultDtoList);
        return page1;
    }


    @Transactional
    @Override
    public Boolean batchDelete(List<Long> sequenceNbrList) {
        for(Long sequenceNbr : sequenceNbrList) {
            if(! this.update(new LambdaUpdateWrapper<EquipmentInform>().eq(EquipmentInform::getSequenceNbr,sequenceNbr).set(EquipmentInform::getIsDelete,true))) {
                throw new BadRequest("删除" + sequenceNbr +"告知书失败");
            }
        }
        return true;
    }

    /**
     * 根据informId 接收告知书
     * @param sequenceNbr
     * @return
     */
    @Transactional
    @Override
    public Boolean acceptInform(Long sequenceNbr) {
        // 接收告知书 更新告知书状态
        Boolean flag = false;
        flag = this.update(new LambdaUpdateWrapper<EquipmentInform>().eq(EquipmentInform::getSequenceNbr,sequenceNbr).set(EquipmentInform::getInformStatus,"9"));
        if(flag) {
            // 更新设备相关参数
            List<InformEquipmentDto> equipmentList = informEquipmentServiceImpl.getEquipListByInformId(sequenceNbr);
            equipmentList.stream().forEach(t -> {
                //  更新设备信息
                Equipment sourceEquip = equipmentServiceImpl.getById(t.getSourceEquipmentId() );
                BeanUtils.copyProperties(t,sourceEquip);
                sourceEquip.setSequenceNbr(t.getSourceEquipmentId());
                equipmentServiceImpl.updateById(sourceEquip);
                // 获取设备附件信息 保存附件信息
                // 原附件信息
                Map<String, List<AttachmentDto>> sourceAttach = sourceFileService.getAttachments(t.getSequenceNbr());
                for(  Map.Entry<String, List<AttachmentDto>> m :sourceAttach.entrySet()) {
                    List<AttachmentDto> tempList = m.getValue();
                    tempList.stream().forEach(l -> {
                        l.setSequenceNbr(null);
                    });
                }
                if(sourceAttach != null) {
                    sourceFileService.saveAttachments(t.getSourceEquipmentId() , sourceAttach);
                }
                // 先删除备份保存的参数信息再保存新参数信息
                iEquipmentIndexInformService.remove(new LambdaQueryWrapper<EquipmentIndexInform>().eq(EquipmentIndexInform::getEquipmentId,sourceEquip.getSequenceNbr()));
                // 备份参数
                List<EquipmentIndex> indexList = equipmentIndexServiceImpl.list(new LambdaQueryWrapper<EquipmentIndex>().eq(EquipmentIndex::getEquipmentId,sourceEquip.getSequenceNbr()));
                indexList.stream().forEach(i -> {
                    EquipmentIndexInform tempIndex = new EquipmentIndexInform();
                    BeanUtils.copyProperties(i,tempIndex);
                    tempIndex.setSequenceNbr(null);
                    iEquipmentIndexInformService.save(tempIndex);
                    equipmentIndexServiceImpl.removeById(i);
                });
                // 保存设备参数信息
                List<EquipmentIndexDto> equipmentIndex = t.getEquipmentIndex();
                if(equipmentIndex != null && equipmentIndex.size()>0) {
                    for(EquipmentIndexDto index : equipmentIndex) {
                        index.setEquipmentId(sourceEquip.getSequenceNbr());
                        index.setEquipmentName(sourceEquip.getName());
                        index.setSequenceNbr(null);
                        equipmentIndexServiceImpl.createWithModel(index);
                    }
                }
            });
        }

        return flag;
    }

    @Transactional
    @Override
    public EquipmentInformDto updateEquipmentInform(EquipmentInformDto model, ReginParams userInfo) {
        if(model.getPlanProductDate() == null) {
            throw new BadRequest("未填写计划施工日期");
        }
        if(( model.getPlanProductDate().getTime() - System.currentTimeMillis() ) < 3*24*60*60*1000 ) {
            throw new BadRequest("计划施工日期比现在时间至少提前3天");
        }
        this.updateWithModel(model);
        saveSourceFile(model);
        EquipmentInform inform = this.getById(model.getSequenceNbr());
        String informStatus = inform.getInformStatus();
        if(EquipmentInformStatusEnum.已驳回.getCode().equals(informStatus)) { // 已驳回重新提交
            try {
                this.startWorkflow(model.getSequenceNbr(),userInfo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            String processStatus = inform.getProcessStatus();
            if(StringUtils.isEmpty(processStatus)) {
                try {
                    this.startWorkflow(model.getSequenceNbr(),userInfo);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if(processStatus.equals(InformWorkFlowEnum.企业撤回告知书.getProcessStatus()) || processStatus.equals(InformWorkFlowEnum.接收方驳回告知书.getProcessStatus())) {
                try {
                    this.reSubmit(model.getSequenceNbr(),userInfo);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return model;
    }

    @Override
    public EquipmentInformDto queryDtoBySeq(Long sequenceNbr) {
        EquipmentInformDto result = this.queryBySeq(sequenceNbr);
        // 封装附件
        Map attachment = sourceFileService.getAttachments(sequenceNbr);
        result.setAttachments(attachment);
        return result;
    }

    @Override
    @Transactional
    public Boolean startWorkflow(Long sequenceNbr, ReginParams userInfo) throws Exception {
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        String businessKey = buildOrderNo();
        JSONObject body = new JSONObject();
        body.put("businessKey", businessKey);
        body.put("processDefinitionKey", processDefinitionKey);
        JSONObject jsonObject = workflowFeignService.startByVariable(body);
        if (jsonObject == null) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        JSONObject instance = jsonObject.getJSONObject("data");
        if (instance == null) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        // 启动流程 后更新状态和流程ID
        // 拿到流程processId
        model.setProcessId(instance.getString("id"));
        InformWorkFlowEnum submit = InformWorkFlowEnum.企业提交审批;
        model.setProcessStatus(submit.getProcessStatus());
        // 其他操作
        // 流程流转
        if (excuteTask(model, userInfo,submit)) {
            model.setInformStatus(EquipmentInformStatusEnum.未接收.getCode());
            this.updateWithModel(model);
            return true;
        } else {
            throw new Exception("执行流程失败");
        }


    }

    @Override
    @Transactional
    public Boolean acceptInform(Long sequenceNbr, ReginParams userInfo) throws Exception {
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        model.setInformStatus("9");
        InformWorkFlowEnum submit = InformWorkFlowEnum.接收方接收告知书;
        model.setProcessStatus(submit.getProcessStatus());
        // 流程流转
        if (excuteTask(model, userInfo,submit)) {
            model.setInformStatus(EquipmentInformStatusEnum.已接收.getCode());
            this.updateWithModel(model);
            this.acceptInform(sequenceNbr);
            return true;
        } else {
            throw new Exception("执行流程失败");
        }
    }

    @Override
    @Transactional
    public Boolean transferInform(Long sequenceNbr, ReginParams userInfo, Long transferUnitId) throws Exception {
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        // company
        CompanyModel companyInfo = Privilege.companyClient.seleteOne(transferUnitId).getResult();
        if(companyInfo!= null) {
            model.setAcceptUnit(companyInfo.getCompanyName());
            model.setAcceptUnitId(transferUnitId);
        }
        InformWorkFlowEnum submit = InformWorkFlowEnum.接收方移交告知书;
        model.setProcessStatus(submit.getProcessStatus());
        // 流程流转
        if (excuteTask(model, userInfo,submit)) {
            this.updateWithModel(model);
            return true;
        } else {
            throw new Exception("执行流程失败");
        }
    }

    @Override
    @Transactional
    public Boolean withdrawInform(Long sequenceNbr, ReginParams userInfo) throws Exception {
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        InformWorkFlowEnum submit = InformWorkFlowEnum.企业撤回告知书;
        model.setProcessStatus(submit.getProcessStatus());
        // 流程流转
        if (excuteTask(model, userInfo,submit)) {
            this.updateWithModel(model);
            return true;
        } else {
            throw new Exception("执行流程失败");
        }
    }

    @Override
    @Transactional
    public Boolean dismissInform(Long sequenceNbr, ReginParams userInfo) throws Exception {
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        InformWorkFlowEnum submit = InformWorkFlowEnum.接收方驳回告知书;
        model.setProcessStatus(submit.getProcessStatus());
        // 流程流转
        if (excuteTask(model, userInfo,submit)) {
            this.updateWithModel(model);
            return true;
        } else {
            throw new Exception("执行流程失败");
        }
    }

    @Override
    @Transactional
    public Boolean cancelInform(Long sequenceNbr, ReginParams userInfo) throws Exception {
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        InformWorkFlowEnum submit = InformWorkFlowEnum.企业撤销告知书;
        model.setProcessStatus(submit.getProcessStatus());
        // 流程流转
        if (excuteTask(model, userInfo,submit)) {
            model.setIsDelete(true);
            this.updateWithModel(model);
            return true;
        } else {
            throw new Exception("执行流程失败");
        }
    }

    @Override
    public Boolean reSubmit(Long sequenceNbr, ReginParams userInfo) throws Exception {
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        InformWorkFlowEnum submit = InformWorkFlowEnum.企业提交审批;
        model.setProcessStatus(submit.getProcessStatus());
        // 流程流转
        if (excuteTask(model, userInfo,submit)) {
            this.updateWithModel(model);
            return true;
        } else {
            throw new Exception("执行流程失败");
        }
    }

    @Override
    public Boolean callbackInform(Long sequenceNbr) {
        // 状态修改为驳回 还原index
        EquipmentInformDto model = this.queryBySeq(sequenceNbr);
        model.setInformStatus(EquipmentInformStatusEnum.已驳回.getCode());
        this.updateWithModel(model);
        // 还原index
        // 更新设备相关参数
        List<InformEquipmentDto> equipmentList = informEquipmentServiceImpl.getEquipListByInformId(sequenceNbr);
        equipmentList.stream().forEach(t -> {
            //  更新设备信息
            Equipment sourceEquip = equipmentServiceImpl.getById(t.getSourceEquipmentId() );

            // 先删除现在参数
            equipmentIndexServiceImpl.remove(new LambdaQueryWrapper<EquipmentIndex>().eq(EquipmentIndex::getEquipmentId,sourceEquip.getSequenceNbr()));

            // 还原备份参数
            List<EquipmentIndexInform> indexList = iEquipmentIndexInformService.list(new LambdaQueryWrapper<EquipmentIndexInform>().eq(EquipmentIndexInform::getEquipmentId,sourceEquip.getSequenceNbr()));
            indexList.stream().forEach(i -> {
                EquipmentIndex tempIndex = new EquipmentIndex();
                BeanUtils.copyProperties(i,tempIndex);
                tempIndex.setSequenceNbr(null);
                equipmentIndexServiceImpl.save(tempIndex);
            });
        });

        return true;
    }

    public boolean excuteTask(EquipmentInformDto model, ReginParams userInfo, InformWorkFlowEnum informWorkFlowEnum) throws Exception {
        HashMap<String, Object> conditionMap = new HashMap<String, Object>();
        conditionMap.put("condition", informWorkFlowEnum.getProcessStatus());
        JSONObject teskObject = workflowFeignService.getTaskList(model.getProcessId());
        if (ObjectUtils.isNotEmpty(teskObject)) {
            JSONArray taskDetailArray = teskObject.getJSONArray("data");
            for (Object obj : taskDetailArray) {
                JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
                workflowFeignService.pickupAndCompleteTask(detail.getString("id"), conditionMap);
            }
        }
        // 更新流程日志
        iInformProcessInfoService.saveProcessInfo(model, userInfo,informWorkFlowEnum.getStage());
        return true;
    }


    public static String buildOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String newDate = sdf.format(new Date());
        String result = "";
        Random random = new Random();
        for (int i = 0; i < 3; i++) {
            result += random.nextInt(10);
        }
        return newDate + result;
    }


    // 保存附件信息
    public void saveSourceFile(EquipmentInformDto model) {
        if (model.getAttachments() != null) {
            sourceFileService.saveAttachments(model.getSequenceNbr(), model.getAttachments());
        }
    }
}