package com.boco.nbd.wios.flow.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.bestvike.linq.Linq;
import com.boco.nbd.cams.core.util.LambdaUtils;
import com.boco.nbd.framework.common.ResponseMessage2;
import com.boco.nbd.framework.common.ResponseStatus;
import com.boco.nbd.framework.workflow.entity.SubmitTypeEnum;
import com.boco.nbd.framework.workflow.entity.TaskInfoResponse;
import com.boco.nbd.framework.workflow.entity.constant.FlowConstants;
import com.boco.nbd.framework.workflow.entity.exception.FlowException;
import com.boco.nbd.wios.export.PoiUtil;
import com.boco.nbd.wios.flow.entity.Constant;
import com.boco.nbd.wios.flow.entity.bo.*;
import com.boco.nbd.wios.flow.entity.po.MenuFieldPO;
import com.boco.nbd.wios.flow.entity.po.OrderInstallPO;
import com.boco.nbd.wios.flow.entity.po.OrderPO;
import com.boco.nbd.wios.flow.entity.po.OrderSurveyPO;
import com.boco.nbd.wios.flow.entity.qo.CamsOrderQo;
import com.boco.nbd.wios.flow.entity.qo.FlowChartQo;
import com.boco.nbd.wios.flow.entity.vo.FlowChartVO;
import com.boco.nbd.wios.flow.entity.vo.RegionInfoVO;
import com.boco.nbd.wios.flow.enums.FiledTypeEnum;
import com.boco.nbd.wios.flow.enums.FlowNodeEnum;
import com.boco.nbd.wios.flow.service.IOrderService;
import com.boco.nbd.wios.flow.util.ProcessUtil;
import com.boco.nbd.wios.manage.entity.bo.Account;
import com.ihidea.core.support.session.SessionInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author:cao hai
 * @date:2022/6/27 11:11
 * @version:V1.0
 * @description:CamsFlowController
 * @modify:
 */
@RestController
@Slf4j
@RequestMapping("/camsFlow")
@Api(tags = "Cams工作流管理")
public class CamsFlowController {

    @Autowired
    private IOrderService orderService;

    @ApiOperation("获取页签chart数据")
    @PostMapping(value = "/getTabChart")
    public ResponseMessage2<List<FlowChartBO>> getTabChart(@RequestBody FlowChartQo qo) {
        ResponseMessage2<FlowChartVO> response = orderService.getFlowChart(qo);
        if (response.getStatus() == 0) {
            return ResponseMessage2.Success2(response.getData().getTabChart());
        }
        return ResponseMessage2.Failed(response.getMessage());
    }


    @ApiOperation("获取单元格chart数据")
    @PostMapping(value = "/getCellChart")
    public ResponseMessage2<List<FlowChartBO>> getCellChart(@RequestBody FlowChartQo qo) {
        ResponseMessage2<FlowChartVO> response = orderService.getFlowChart(qo);
        if (response.getStatus() == 0) {
            return ResponseMessage2.Success2(response.getData().getCellChart());
        }
        return ResponseMessage2.Failed(response.getMessage());
    }

    @ApiOperation("获取区域信息")
    @GetMapping(value = "/getRegionInfo")
    public ResponseMessage2 getRegionInfo(Integer regionId) {
        Map<Integer, RegionInfoVO> items = orderService.getRegionInfo();
        if (regionId != null) {
            return ResponseMessage2.Success2(items.get(regionId));
        }
        return ResponseMessage2.Success2(items);


    }

    @ApiOperation("获取配置:configName为空获取全量")
    @GetMapping(value = "/getConfigDic")
    public ResponseMessage2 getConfigDic(String configName) {
        Map<String, Map<Object, String>> maps = orderService.createEnumMap();
        if (StrUtil.isNotEmpty(configName)) {
            return ResponseMessage2.Success2(maps.get(configName));
        }
        return ResponseMessage2.Success2(maps);
    }

    @ApiOperation("根据考核部分Id获取评分算法,为空获取全部算法")
    @GetMapping(value = "/getScoreAlgorithm")
    public ResponseMessage2 getScoreAlgorithm(Integer parentKey) {
        return ResponseMessage2.Success2(orderService.getScoreAlgorithm(parentKey));
    }

    @ApiOperation("根据报告配置项目内容,为空获取全部,例如:parentKey=1,勘测,parentKey=2 安装")
    @GetMapping(value = "/getReportEntry")
    public ResponseMessage2 getReportEntry(Integer parentKey) {
        return ResponseMessage2.Success2(orderService.getReportEntry(parentKey));
    }


    @ApiOperation("获取列表字段信息")
    @RequestMapping(value = "/getFieldInfo", method = {RequestMethod.GET})
    public ResponseMessage2<List<ColumnBO>> getFieldInfo(String menuId) {
        List<MenuFieldPO> fields = orderService.getMenuFields(menuId);
        return ResponseMessage2.Success2(ProcessUtil.creatListField(fields));
    }


    /**
     * 数据查询
     *
     * @param qo
     * @return
     */
    private ResponseMessage2<WorkTaskVO> getWorkTaskHandle(CamsOrderQo qo) {
        try {
            commonHandle(qo);
            //由于列表部分功能属于半成品,所以存在根据menuId识别硬编码的代码
            switch (qo.getMenuId()) {
                //待办列表:需派单订单,需审核订单,勘测订单,安装订单
                case "1001":
                case "1101":
                    break;
                case "1002":
                    qo.setNext(FlowNodeEnum.NODE_102.getKey() + "");
                    break;
                //勘察资料审核“、“安装资料审核
                case "1003":
                    qo.setNext(FlowNodeEnum.NODE_107.getKey() + FlowConstants.COMMA + FlowNodeEnum.NODE_112.getKey());
                    break;
                //接单列表、“勘测预约“、“勘测完成”、“上传勘测资料
                case "1004":
                    qo.setNext(FlowNodeEnum.NODE_103.getKey() + FlowConstants.COMMA + FlowNodeEnum.NODE_104.getKey() + FlowConstants.COMMA + FlowNodeEnum.NODE_105.getKey()
                            + FlowConstants.COMMA + FlowNodeEnum.NODE_106.getKey());
                    break;
                //安装预约“、“安装完成"、上传安装资料
                case "1005":
                    qo.setNext(FlowNodeEnum.NODE_108.getKey() + FlowConstants.COMMA + FlowNodeEnum.NODE_109.getKey() + FlowConstants.COMMA + FlowNodeEnum.NODE_110.getKey()
                            + FlowConstants.COMMA + FlowNodeEnum.NODE_111.getKey());
                    break;
                //已办列表
                case "1010":
                case "1110":
                    return ResponseMessage2.Success2(orderService.getMyFinishedWorkTask(qo));
                //归档列表
                case "1020":
                case "1120":
                    return ResponseMessage2.Success2(orderService.getArchivedWorkTask(qo));
                default:
                    return ResponseMessage2.Failed("unrealized " + qo.getMenuId() + " method.");
            }
            return ResponseMessage2.Success2(orderService.getWaitDealWorkTask(qo));
        } catch (FlowException ex) {
            log.error("getWorkTask:" + ex);
            int code = ProcessUtil.RE_LOGIN.equals(ex.getMessage()) ? ResponseStatus.ForbiddenAccess.getIndex() : ResponseStatus.Fail.getIndex();
            return ResponseMessage2.Failed(code, ex.getMessage());
        } catch (Exception e) {
            log.error("getWorkTask:" + e);
            return ResponseMessage2.Failed(e.getMessage());
        }
    }

    @ApiOperation("获取列表数据")
    @PostMapping(value = "/getWorkTask")
    public ResponseMessage2<WorkTaskVO> getWorkTask(@RequestBody CamsOrderQo qo) {
        return getWorkTaskHandle(qo);
    }


    @ApiOperation("导出列表")
    @GetMapping(value = "/exportWorkTask")
    public void exportWorkTask(HttpServletResponse response, CamsOrderQo qo) {
        try {
            qo.setAreExport(true);
            qo.setIsPaged(false);
            log.info("start exportWorkTask");
            ResponseMessage2<WorkTaskVO> data = getWorkTaskHandle(qo);
            log.info("end getWorkTask");
            if (data.getStatus() != 0) {
                log.error("exportWorkTask::" + data.getMessage());
                return;
            }
            WorkTaskVO vo = data.getData();
            List<MenuFieldBO> fields = qo.getFields();
            //不具备用户号码导出权限=>剔除userPhone
            if (!orderService.hasExportUserPhone(qo.getAccount())) {
                MenuFieldBO fieldBo = Linq.of(fields).where(s -> s.getDataIndex().equals(Constant.USER_PHONE)).firstOrDefault();
                if (fieldBo != null) {
                    fields.remove(fieldBo);
                }
            }
            String[] fieldStrArray = Linq.of(qo.getFields()).select(s -> s.getDataIndex()).toArray(String.class);
            String[][] titleArray = new String[][]{Linq.of(qo.getFields()).select(s -> s.getTitle()).toArray(String.class)};
            String fileName = "订单明细" + DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN);
            List<?> exportList = vo.getTaskList();
            PoiUtil.exportExcelToWebsite(response, fileName, titleArray, fieldStrArray, exportList);

        } catch (Exception e) {
            log.error("exportWorkTask::" + e);
        }
    }

    @ApiOperation("获取流转轨迹")
    @RequestMapping(value = "/getTaskTracks", method = {RequestMethod.GET})
    public ResponseMessage2<List<TaskInfoResponse>> getWorkTrack(String processInsId) {
        try {
            return ResponseMessage2.Success2(orderService.getWorkTrack(processInsId));
        } catch (Exception e) {
            log.error("WorkflowController.getWorkTrack::" + e);
            return ResponseMessage2.Failed(e.getMessage());
        }
    }

    @ApiOperation("获取表单操作界面数据=>nodeFlag业务暂时未附加")
    @GetMapping("/getBusinessData")
    public ResponseMessage2 getBusinessData(@RequestParam(value = "nodeFlag") Integer nodeFlag, @RequestParam(value = "workId") String workId) {
        FlowNodeEnum nodeEnum = FlowNodeEnum.getEnum(nodeFlag);
        if (nodeEnum == null) {
            return ResponseMessage2.Failed("未识别节点标识:" + nodeFlag);
        }
        return ResponseMessage2.Success2(orderService.getBusinessData(workId));
    }

    @ApiOperation("更新业务数据==>持续完善中")
    @PostMapping("/updateBusinessData")
    public ResponseMessage2<Boolean> updateBusinessData(@RequestBody UpdateBusinessBO bo) {
        try {
            bo.localVerify();
            BusinessDataBO business = new BusinessDataBO();
            business.setWorkId(bo.getWorkId());
            business.setBusiness(ProcessUtil.fillBeanWithMap(bo.getFormData(), OrderPO.class));
            business.setBusinessSurvey(ProcessUtil.fillBeanWithMap(bo.getFormData(), OrderSurveyPO.class));
            business.setBusinessInstall(ProcessUtil.fillBeanWithMap(bo.getFormData(), OrderInstallPO.class));
            if (business.getBusiness() == null && business.getBusinessSurvey() == null && business.getBusinessInstall() == null) {
                return ResponseMessage2.Failed("表单数据无法隐射到实体.");
            }
            orderService.updateBusinessData(business);
        } catch (Exception ex) {
            return ResponseMessage2.Failed(ex.getMessage());
        }
        return ResponseMessage2.Success();
    }

    @ApiOperation("工单转派")
    @PostMapping("/transferFlow")
    public ResponseMessage2<Boolean> transferFlow(@RequestBody TransferFlowBO submitBO) {
        try {
            LocalSubmitFlowBO flowBO = submitBO.toBo();
            flowBO.setSubmitType(SubmitTypeEnum.Transfer);
            return submitFlow(flowBO);
        } catch (Exception ex) {
            log.error("transferFlow FlowException:", ex);
            return ResponseMessage2.Failed(ex.getMessage());
        }
    }

    @ApiOperation("流程关闭")
    @PostMapping("/closeFlow")
    public ResponseMessage2<Boolean> closeFlow(@RequestBody BaseSubmitFlowBO submitBO) {
        LocalSubmitFlowBO flowBO = submitBO.toBo();
        flowBO.setSubmitType(SubmitTypeEnum.CloseFlow);
        return submitFlow(flowBO);
    }

    @ApiOperation("流程流转")
    @PostMapping("/submitFlow")
    public ResponseMessage2<Boolean> submitFlow(@RequestBody SimpleSubmitFlowBO submitBO) {
        LocalSubmitFlowBO flowBO = submitBO.toBo();
        if (submitBO.getUpdateBusiness() != null && submitBO.getUpdateBusiness()) {
            flowBO.setSubmitType(SubmitTypeEnum.UpdateVariable);
        } else {
            flowBO.setSubmitType(SubmitTypeEnum.TaskFlow);
        }
        return submitFlow(flowBO);
    }

    /**
     * 流转接口
     *
     * @param bo
     * @return
     */
    private ResponseMessage2<Boolean> submitFlow(LocalSubmitFlowBO bo) {
        try {
            SessionInfo currentUser = ProcessUtil.getUserInfo();
            if (null == currentUser) {
                return ResponseMessage2.Failed(ResponseStatus.ForbiddenAccess.getIndex(), ProcessUtil.RE_LOGIN);
            }
            bo.setSubmitUserId(currentUser.getUserId());
            bo.setSubmitUserName(currentUser.getUserName());
            return orderService.submitFlow(bo);
        } catch (FlowException ex) {
            log.error("submitFlow FlowException:", ex);
            return ResponseMessage2.Failed(ex.getMessage());
        } catch (Exception ex) {
            log.error("submitFlow Exception:", ex);
            return ResponseMessage2.Failed(ex.getMessage());
        }
    }

    /**
     * 统一处理接口
     *
     * @param qo
     */
    private void commonHandle(CamsOrderQo qo) {
        SessionInfo currentUser = ProcessUtil.getUserInfo();
        if (currentUser == null) {
            throw new FlowException(ProcessUtil.RE_LOGIN);
        }
        qo.setUserId(currentUser.getUserId());
        qo.setLoginUserName(currentUser.getUserName());
        qo.setAccount(currentUser.getAttribute(LambdaUtils.getFieldName(Account::getAccount)));
        if (StrUtil.isEmpty(qo.getMenuId())) {
            throw new FlowException("menuId参数缺失");
        }
        List<MenuFieldPO> fields = orderService.getMenuFields(qo.getMenuId());
        if (fields == null || fields.isEmpty()) {
            throw new FlowException(qo.getMenuId() + " 参数列表字段参数缺失配置");
        }
        List<MenuFieldBO> list;
        FiledTypeEnum filedTypeEnum = Convert.toBool(qo.getAreExport(), false) ? FiledTypeEnum.EXPORT_FIELD : FiledTypeEnum.TABLE_FIELD;
        list = Linq.of(fields).where(s -> filedTypeEnum.getKey().equals(s.getFiledType())).orderBy(x -> x.getOrder()).toList().stream().map(s -> s.toBaseField()).collect(Collectors.toList());
        if (list == null || list.isEmpty()) {
            throw new FlowException("参数列表字段参数缺失配置");
        }

        qo.setFields(list);
    }

}