package com.yeejoin.amos.boot.module.jyjc.biz.service.impl;

import cn.hutool.core.map.MapBuilder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.common.api.dto.AttachmentDto;
import com.yeejoin.amos.boot.module.jyjc.api.common.CommonConstants;
import com.yeejoin.amos.boot.module.jyjc.api.entity.JyjcOpeningApplication;
import com.yeejoin.amos.boot.module.jyjc.api.mapper.JyjcBaseMapper;
import com.yeejoin.amos.boot.module.jyjc.api.mapper.JyjcOpeningApplicationMapper;
import com.yeejoin.amos.boot.module.jyjc.api.service.IJyjcOpeningApplicationService;
import com.yeejoin.amos.boot.module.jyjc.api.model.JyjcOpeningApplicationModel;
import com.yeejoin.amos.boot.module.jyjc.biz.config.BaseException;
import com.yeejoin.amos.boot.module.jyjc.biz.config.CommonException;
import com.yeejoin.amos.boot.module.jyjc.biz.feign.WorkflowFeignClient;
import com.yeejoin.amos.boot.module.tcm.api.dto.TzBaseEnterpriseInfoDto;
import com.yeejoin.amos.boot.module.tcm.api.dto.TzBaseUnitLicenceDto;
import com.yeejoin.amos.boot.module.tcm.api.dto.TzsUserInfoDto;
import com.yeejoin.amos.boot.module.tcm.api.entity.TzBaseEnterpriseInfo;
import com.yeejoin.amos.boot.module.tcm.api.entity.TzsUserInfo;
import com.yeejoin.amos.boot.module.tcm.api.enums.LicenceTypeEnum;
import com.yeejoin.amos.boot.module.tcm.api.mapper.TzBaseEnterpriseInfoMapper;
import com.yeejoin.amos.boot.module.tcm.api.mapper.TzBaseUnitLicenceMapper;
import com.yeejoin.amos.boot.module.tcm.api.mapper.TzsUserInfoMapper;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.workflow.Workflow;
import com.yeejoin.amos.feign.workflow.model.ActWorkflowStartDTO;
import com.yeejoin.amos.feign.workflow.model.AjaxResult;
import com.yeejoin.amos.feign.workflow.model.TaskResultDTO;
import org.apache.commons.lang3.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.bouncycastle.cert.ocsp.Req;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
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 javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 服务实现类
 *
 * @author system_generator
 * @date 2023-12-13
 */
@Service
@Slf4j
public class JyjcOpeningApplicationServiceImpl extends BaseService<JyjcOpeningApplicationModel, JyjcOpeningApplication, JyjcOpeningApplicationMapper> implements IJyjcOpeningApplicationService {

    @Autowired
    CommonserviceImpl commonserviceImpl;

    @Autowired
    JyjcOpeningApplicationMapper jyjcOpeningApplicationMapper;

    @Resource (type = JyjcBaseMapper.class)
    private JyjcBaseMapper baseMapper;

    @Value ("${process-definition-key.jyjc.openapplication:}")
    private String processDefinitionKey;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private TzBaseUnitLicenceMapper unitLicenceMapper;
    @Autowired
    private TzBaseEnterpriseInfoMapper enterpriseInfoMapper;
    @Autowired
    private TzsUserInfoMapper userInfoMapper;

    @Autowired
    private WorkflowFeignClient workflowFeignClient;

    @Transactional (rollbackFor = {Exception.class, BaseException.class})
    public JyjcOpeningApplicationModel saveOrUpdateModel(JyjcOpeningApplicationModel model, Boolean enableStartFlow) {
        try {
            if (enableStartFlow) {
                // 开启工作流 startProcess
                String instanceId = startFlow();
                JSONObject dataObject = getTask(instanceId);
                JSONArray executorArray = dataObject.getJSONObject("nodeInfo").getJSONArray("executor");
                if(!ValidationUtil.isEmpty(executorArray)) {
                    String roleGroups = executorArray.stream().map(json -> Optional.ofNullable(((LinkedHashMap) json).get("groupId")).orElse("").toString()).collect(Collectors.joining(","));
                    model.setWorkflowRole(roleGroups);
                }
                model.setStatus(!ValidationUtil.isEmpty(dataObject) && !ValidationUtil.isEmpty(dataObject.get("status")) ? String.valueOf(dataObject.get("status")) : "");
                model.setWorkflowProstanceId(instanceId);
            }
            if (model.getSequenceNbr() == null) {
                CompanyBo companyBo = commonserviceImpl.getReginParamsOfCurrentUser().getCompany();
                model.setUnitCode(companyBo.getCompanyCode());
                model.setUnitCode("91611103MAC4Q1EG7B");
                model.setUnitCodeName(companyBo.getCompanyName());
                model.setApplicationSeq(buildApplicationSeq());
                return this.createWithModel(model);
            } else {
                return this.updateWithModel(model);
            }
        } catch (Exception e) {
            log.error("saveModel: model={} error", model, e);
            throw new BaseException(e.getMessage());
        }
    }

    public void updateModelByInstanceId(String instanceId) {
        log.info("updateModelByInstanceId, instanceId={}", instanceId);
        JyjcOpeningApplication entity = this.lambdaQuery().eq(JyjcOpeningApplication::getWorkflowProstanceId, instanceId).one();
        if (entity == null) {
            return;
        }
        JSONObject taskJson = getTask(instanceId);
        log.info("taskJson => {}", taskJson);
        entity.setWorkflowRole(getWorkflowRoleGroups(taskJson));
        entity.setStatus(getWorkflowStatus(taskJson));
        this.updateById(entity);
    }

    private String getWorkflowStatus(JSONObject dataObject) {
        return !ValidationUtil.isEmpty(dataObject) && !ValidationUtil.isEmpty(dataObject.get("status")) ? String.valueOf(dataObject.get("status")) : "";
    }

    private String getWorkflowRoleGroups(JSONObject dataObject) {
        JSONArray executorArray = dataObject.getJSONObject("nodeInfo").getJSONArray("executor");
        if(!ValidationUtil.isEmpty(executorArray)) {
            return executorArray.stream().map(json -> Optional.ofNullable(((LinkedHashMap) json).get("groupId")).orElse("").toString()).collect(Collectors.joining(","));
        }
        return null;
    }

    private JSONObject getTask(String instanceId) {
        AjaxResult ajaxResult = Workflow.taskClient.getTask(instanceId);
        JSONObject dataObject = JSON.parseObject(JSON.toJSONString(ajaxResult.get("data")));
        String taskId = dataObject.getString("id");// 工作流ID
        FeignClientResult<JSONObject> nodeInfo = workflowFeignClient.getNodeInfotoken(RequestContext.getAppKey(), RequestContext.getProduct(), RequestContext.getToken(), taskId);
        dataObject.put("nodeInfo", nodeInfo.getResult());
        return dataObject;
    }

    /**
     * 分页查询
     */

    public Page<JyjcOpeningApplicationModel> queryForJyjcOpeningApplicationPage(Page<JyjcOpeningApplicationModel> page) {
        return this.queryForPage(page, null, false);
    }

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

    public Page<JyjcOpeningApplicationModel> queryForJyjcOpeningApplicationPage(Page<JyjcOpeningApplication> page, JyjcOpeningApplicationModel jyjcOpeningApplicationModel) {
        //根据申请单中的单位信息对于列表数据进行过滤
        CompanyBo companyBo = commonserviceImpl.getReginParamsOfCurrentUser().getCompany();
        if (companyBo.getLevel().equals("company")) {
            jyjcOpeningApplicationModel.setUnitCode(companyBo.getCompanyCode());
        }
        return jyjcOpeningApplicationMapper.selectJyjcOpeningApplicationList(page, jyjcOpeningApplicationModel);
    }


    /**
     * 获取详情跳转
     *
     * @param
     * @return {@link }
     * @throws
     * @author yangyang
     */
    public JyjcOpeningApplicationModel queryDetail(Long sequenceNbr) {
        ReginParams reginParams = commonserviceImpl.getReginParamsOfCurrentUser();
        if (ValidationUtil.isEmpty(reginParams.getCompany())) {
            throw new RuntimeException("未指定人员归属单位信息");
        }
        JyjcOpeningApplicationModel jyjcOpeningApplicationModel;
        if (null != sequenceNbr) {
            jyjcOpeningApplicationModel = this.queryBySeq(sequenceNbr);
        } else {
            jyjcOpeningApplicationModel = new JyjcOpeningApplicationModel();
        }
        String unitCode = reginParams.getCompany().getCompanyCode();
        unitCode="91611103MAC4Q1EG7B"; // 测试用，之后务必删除！！！
        QueryWrapper enterpriseInfoQueryWrapper = new QueryWrapper<>();
        enterpriseInfoQueryWrapper.eq("use_code", unitCode);
        TzBaseEnterpriseInfo baseUnitLicenceEntity = enterpriseInfoMapper.selectOne(enterpriseInfoQueryWrapper);
        // 获取企业资质
        if (baseUnitLicenceEntity != null) {
            jyjcOpeningApplicationModel.setUseContact(baseUnitLicenceEntity.getUseContact());
            jyjcOpeningApplicationModel.setContactPhone(baseUnitLicenceEntity.getContactPhone());
            jyjcOpeningApplicationModel.setIndustrySupervisor(baseUnitLicenceEntity.getIndustrySupervisor());
            jyjcOpeningApplicationModel.setLongitude(baseUnitLicenceEntity.getLongitude());
            jyjcOpeningApplicationModel.setLatitude(baseUnitLicenceEntity.getLatitude());
            if(ObjectUtils.isNotEmpty(baseUnitLicenceEntity.getUnitBusinessLicense())) {
                jyjcOpeningApplicationModel.setUnitBusinessLicense(JSONArray.parseArray(baseUnitLicenceEntity.getUnitBusinessLicense(), AttachmentDto.class));
            }
        }
        // QueryWrapper unitLicenceQueryWrapper = new QueryWrapper<>();
        // unitLicenceQueryWrapper.eq("unit_code", unitCode);
        // unitLicenceQueryWrapper.eq("licence_type", LicenceTypeEnum.JYJC.getCode());
        // List<TzBaseUnitLicenceDto> baseUnitLicences = Bean.toModels(unitLicenceMapper.selectList(unitLicenceQueryWrapper), TzBaseUnitLicenceDto.class );
        //
        List<TzBaseUnitLicenceDto> baseUnitLicences = baseMapper.selectBaseUnitLicenceList(MapBuilder.<String, Object>create()
                .put("unitCode", unitCode)
                // .put("licenceType", LicenceTypeEnum.JYJC.getCode())
                                                                                                     .build());
        jyjcOpeningApplicationModel.setBaseUnitLicences(baseUnitLicences);
        // 获取检验人员信息
        QueryWrapper userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("unit_code", unitCode);
        List<TzsUserInfo> userInfos = userInfoMapper.selectList(userInfoQueryWrapper);
        if (!ValidationUtil.isEmpty(userInfos)) {
            List<String> codes = userInfos.stream()
                                       .map(o -> o.getPost() != null ? JSON.parseArray(o.getPost(), String.class) : null)
                                       .filter(Objects::nonNull)
                                       .collect(Collectors.toList())
                                       .stream().flatMap(o -> o.stream()).distinct().collect(Collectors.toList());
            List<Map<String, String>> dicts = baseMapper.selectDataDictionaryList(codes);
            List<TzsUserInfoDto> userInfoDtos = userInfos.stream().map(o -> {
                TzsUserInfoDto dto = new TzsUserInfoDto();
                Bean.toModel(o, dto);
                if (o.getPost() != null) {
                   List<String> temps = JSON.parseArray(o.getPost(), String.class);
                   String postName = temps.stream().map(m -> dicts.stream().filter(dict -> dict.get("code").equals(m)).findFirst().map(n -> n.get("name")).orElse("")).collect(Collectors.joining(","));
                   dto.setPostName(postName);
                }
                return dto;
            }).collect(Collectors.toList());
            jyjcOpeningApplicationModel.setUserInfos(userInfoDtos);
        }
        return jyjcOpeningApplicationModel;
    }

    public String startFlow() throws Exception {
        // 重新开启工作流
        ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
        dto.setProcessDefinitionKey(processDefinitionKey);
        dto.setBusinessKey("1");
        AjaxResult ajaxResult = Workflow.taskClient.startByVariable(dto);
        if (log.isDebugEnabled()) {
            log.debug("开启工作流结果：{}", ajaxResult);
        }
        if (ajaxResult == null || (ajaxResult.get(AjaxResult.CODE_TAG) != null && !"200".equals(ajaxResult.get(AjaxResult.CODE_TAG).toString()))) {
            throw new BaseException("开启工作流错误");
        }
        String instanceId = ((Map) ajaxResult.get("data")).get("id").toString();
        return instanceId;
    }

    /**
     * 接收/驳回通知检验单
     */
   public void execueFlow(Map<String,Object> params) {
       String op = params.get("op").toString();
       String instanceId = params.get("instanceId").toString();
       String comments= params.get("comments").toString();
        try {
            AjaxResult ajaxResult = Workflow.taskClient.getTask(instanceId);
            JSONObject dataObject = JSON.parseObject(JSON.toJSONString(ajaxResult.get("data")));
            String taskId = dataObject.getString("id");
            //组装信息
            TaskResultDTO dto = new TaskResultDTO();
//            dto.setResult(op);
            dto.setResultCode("approvalStatus");
            dto.setTaskId(taskId);
            HashMap<String,Object> varibalble = new HashMap<>();
            varibalble.put("approvalStatus",op);
            dto.setVariable(varibalble);
            dto.setComment(comments);
            //执行流程
            AjaxResult ajaxResult1 = Workflow.taskClient.completeByTask(taskId, dto);
            if (ObjectUtils.isEmpty(ajaxResult1)) {

            }
            updateModelByInstanceId(instanceId);
            if(op.equals("0")){
                String originalDataId = params.get("originalDataId").toString();
                JyjcOpeningApplication jyjcOpeningApplication=jyjcOpeningApplicationMapper.selectById(originalDataId);
                List<String> detectionRegion = Arrays.asList(params.get("detectionRegion").toString().split(",")) ;
                String detectionRegionName =  params.get("detectionRegionName").toString();
                jyjcOpeningApplication.setDetectionRegion(detectionRegion);
                jyjcOpeningApplication.setDetectionRegionName(detectionRegionName);
                jyjcOpeningApplicationMapper.updateById(jyjcOpeningApplication);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /**
     * 撤回流程办理单
     */
   public void stopFlow(String instanceId) {
        try {
            //撤回流程
            AjaxResult ajaxResult1 = Workflow.taskClient.stopProcess(instanceId);
            if (ObjectUtils.isEmpty(ajaxResult1)) {

            }
            updateModelByInstanceId(instanceId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * JY+年（4位）+月（2位）+日（2位）+序列号（3位
     *
     * @param
     * @return {@link  java.lang.String}
     * @throws
     * @author yangyang
     * @date 2023/12/13 22:30
     */
    private String buildApplicationSeq() {
        String sdf = new SimpleDateFormat("yyyyMMdd").format(new Date());
        long increment = redisUtils.incr(CommonConstants.OPEN_APPLICATION_SEQ_KEY, 1);
        if (increment == 0) {
            redisUtils.expire(CommonConstants.OPEN_APPLICATION_SEQ_KEY, nextDay());
        }
        return CommonConstants.APPLICATION_SEQ_PREFIX + sdf + String.format("%03d", increment);
    }

    private long nextDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        return (calendar.getTimeInMillis() - System.currentTimeMillis()) / 1000;
    }

}