package com.yunzhupaas.flowable.controller;


import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.ImmutableList;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.controller.SuperController;
import com.yunzhupaas.base.entity.DictionaryDataEntity;
import com.yunzhupaas.base.entity.VisualdevEntity;
import com.yunzhupaas.base.vo.DownloadVO;
import com.yunzhupaas.base.vo.ListVO;
import com.yunzhupaas.base.vo.PageListVO;
import com.yunzhupaas.base.vo.PaginationVO;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.constant.PermissionConst;
import com.yunzhupaas.emnus.ModuleTypeEnum;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.flowable.entity.TemplateEntity;
import com.yunzhupaas.flowable.entity.TemplateJsonEntity;
import com.yunzhupaas.flowable.model.candidates.CandidateUserVo;
import com.yunzhupaas.flowable.model.template.*;
import com.yunzhupaas.flowable.model.templatejson.FlowListModel;
import com.yunzhupaas.flowable.model.templatejson.TemplateJsonInfoVO;
import com.yunzhupaas.flowable.model.templatejson.TemplateJsonSelectVO;
import com.yunzhupaas.flowable.model.templatenode.TemplateNodeCrFrom;
import com.yunzhupaas.flowable.model.templatenode.TemplateNodeUpFrom;
import com.yunzhupaas.flowable.service.CommonService;
import com.yunzhupaas.flowable.service.OperatorService;
import com.yunzhupaas.flowable.service.TemplateJsonService;
import com.yunzhupaas.flowable.service.TemplateService;
import com.yunzhupaas.flowable.util.ServiceUtil;
import com.yunzhupaas.model.FlowWorkListVO;
import com.yunzhupaas.permission.entity.OrganizeEntity;
import com.yunzhupaas.permission.entity.UserEntity;
import com.yunzhupaas.permission.entity.UserRelationEntity;
import com.yunzhupaas.permission.model.user.WorkHandoverModel;
import com.yunzhupaas.util.FileUtil;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.RandomUtil;
import com.yunzhupaas.util.UploaderUtil;
import com.yunzhupaas.workflow.service.TemplateApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Tag(name = "流程模板", description = "flowTemplate")
@RestController
@RequestMapping("/api/workflow/template")
public class TemplateController extends SuperController<TemplateService, TemplateEntity> implements TemplateApi {

    @Autowired
    private TemplateService templateService;
    @Autowired
    private TemplateJsonService templateJsonService;
    @Autowired
    private ServiceUtil serviceUtil;
    @Autowired
    private CommonService commonService;
    @Autowired
    private OperatorService operatorService;

    /**
     * 流程列表
     *
     * @param pagination 分页模型
     * @return
     */
    @Operation(summary = "流程列表")
    @GetMapping
    public ActionResult<PageListVO<TemplatePageLisVO>> list(TemplatePagination pagination) {
        List<TemplateEntity> list = templateService.getList(pagination);
        List<DictionaryDataEntity> dictionList = serviceUtil.getDictionName(list.stream().map(TemplateEntity::getCategory).collect(Collectors.toList()));
        List<UserEntity> userList = serviceUtil.getUserName(list.stream().map(TemplateEntity::getCreatorUserId).collect(Collectors.toList()));
        List<TemplatePageLisVO> listVO = new ArrayList<>();
        for (TemplateEntity entity : list) {
            TemplatePageLisVO vo = JsonUtil.getJsonToBean(entity, TemplatePageLisVO.class);
            DictionaryDataEntity dataEntity = dictionList.stream().filter(t -> t.getId().equals(entity.getCategory())).findFirst().orElse(null);
            vo.setCategory(dataEntity != null ? dataEntity.getFullName() : "");
            UserEntity userEntity = userList.stream().filter(t -> t.getId().equals(entity.getCreatorUserId())).findFirst().orElse(null);
            vo.setCreatorUser(userEntity != null ? userEntity.getRealName() + "/" + userEntity.getAccount() : "");
            listVO.add(vo);
        }
        PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
        return ActionResult.page(listVO, paginationVO);
    }

    /**
     * 流程列表
     *
     * @param pagination 分页模型
     * @return
     */
    @Operation(summary = "流程列表")
    @GetMapping("/Selector")
    public ActionResult<PageListVO<TemplatePageModel>> selector(TemplatePagination pagination) {
        List<TemplatePageVo> list = templateService.getSelector(pagination);
        List<TemplatePageModel> voList = JsonUtil.getJsonToList(list, TemplatePageModel.class);
        PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
        return ActionResult.page(voList, paginationVO);
    }

    /**
     * 常用流程树
     */
    @Operation(summary = "常用流程树")
    @GetMapping("/CommonFlowTree")
    public ActionResult getTreeCommon() {
        ListVO<TemplateTreeListVo> vo = new ListVO<>();
        vo.setList(templateService.getTreeCommon());
        return ActionResult.success(vo);
    }

    /**
     * 树形列表
     */
    @Operation(summary = "树形列表")
    @GetMapping("/TreeList")
    public ActionResult<ListVO<TemplateTreeListVo>> treeList(@RequestParam(value = "formType", required = false) Integer formType) {
        ListVO<TemplateTreeListVo> vo = new ListVO<>();
        vo.setList(templateService.treeList(formType));
        return ActionResult.success(vo);
    }

    /**
     * 权限树形集合
     */
    @Operation(summary = "权限树形列表")
    @GetMapping("/Power/TreeList")
    public ActionResult<List<TemplateTreeListVo>> treeListPower() {
        return ActionResult.success(templateService.treeListWithPower());
    }

    /**
     * 流程基础信息
     *
     * @param id 主键
     * @return
     */
    @Operation(summary = "流程基础信息")
    @GetMapping("/{id}")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    public ActionResult<TemplateInfoVO> info(@PathVariable("id") String id) throws WorkFlowException {
        TemplateEntity entity = templateService.getInfo(id);
        TemplateInfoVO vo = JsonUtil.getJsonToBean(entity, TemplateInfoVO.class);
        return ActionResult.success(vo);
    }

    /**
     * 流程版本列表
     *
     * @param id 主键
     * @return
     */
    @Operation(summary = "流程版本列表")
    @GetMapping("/Version/{id}")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    public ActionResult<List<TemplateJsonSelectVO>> version(@PathVariable("id") String id) throws WorkFlowException {
        List<TemplateJsonEntity> list = templateJsonService.getList(id);
        List<TemplateJsonSelectVO> listVO = new ArrayList<>();
        for (TemplateJsonEntity jsonEntity : list) {
            TemplateJsonSelectVO vo = JsonUtil.getJsonToBean(jsonEntity, TemplateJsonSelectVO.class);
            vo.setFlowVersion(jsonEntity.getVersion());
            vo.setFullName("流程版本V" + jsonEntity.getVersion());
            listVO.add(vo);
        }
        return ActionResult.success(listVO);
    }

    /**
     * 流程模板信息
     *
     * @param id 主键
     * @return
     */
    @Operation(summary = "流程模板信息")
    @GetMapping("/Info/{id}")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    public ActionResult<TemplateJsonInfoVO> templateJsonInfo(@PathVariable("id") String id) throws WorkFlowException {
        return ActionResult.success(templateJsonService.getInfoVo(id));
    }

    /**
     * 新建流程
     *
     * @param form 流程模型
     * @return
     */
    @Operation(summary = "新建流程")
    @PostMapping
    @Parameters({
            @Parameter(name = "form", description = "流程模型", required = true),
    })
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult create(@RequestBody @Valid TemplateNodeCrFrom form) throws WorkFlowException {
        TemplateEntity entity = JsonUtil.getJsonToBean(form, TemplateEntity.class);
        String flowConfig = form.getFlowConfig();
        FlowConfigModel config = JsonUtil.getJsonToBean(flowConfig, FlowConfigModel.class);
        config = config == null ? new FlowConfigModel() : config;
        entity.setVisibleType(config.getVisibleType());
        templateService.create(entity, form.getFlowXml(), form.getFlowNodes());
        return ActionResult.success(MsgCode.SU001.get(), entity.getId());
    }

    /**
     * 更新流程
     *
     * @param id   主键
     * @param form 流程模型
     * @return
     */
    @Operation(summary = "更新流程")
    @PutMapping("/{id}")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
            @Parameter(name = "form", description = "流程模型", required = true),
    })
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult update(@PathVariable("id") String id, @RequestBody @Valid TemplateNodeUpFrom form) throws WorkFlowException {
        TemplateEntity entity = JsonUtil.getJsonToBean(form, TemplateEntity.class);
        String flowConfig = form.getFlowConfig();
        FlowConfigModel config = JsonUtil.getJsonToBean(flowConfig, FlowConfigModel.class);
        config = config == null ? new FlowConfigModel() : config;
        entity.setVisibleType(config.getVisibleType());
        templateService.update(id, entity);
        return ActionResult.success(MsgCode.SU004.get());
    }

    /**
     * 更新流程类型
     *
     * @param id 主键
     */
    @Operation(summary = "更新流程类型")
    @PutMapping("/{id}/UpdateType")
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult updateType(@PathVariable("id") String id) throws WorkFlowException {
        TemplateEntity entity = templateService.getInfo(id);
        entity.setType(0);
        templateService.updateById(entity);
        return ActionResult.success(MsgCode.SU004.get());
    }

    /**
     * 删除流程引擎
     *
     * @param id 主键
     * @return
     */
    @Operation(summary = "删除流程引擎")
    @DeleteMapping("/{id}")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult delete(@PathVariable("id") String id) throws WorkFlowException {
        TemplateEntity entity = templateService.getInfo(id);
        templateService.delete(entity);
        return ActionResult.success(MsgCode.SU003.get());
    }

    /**
     * 删除流程版本
     *
     * @param id 主键
     * @return
     */
    @Operation(summary = "删除流程版本")
    @DeleteMapping("/Info/{id}")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult deleteInfo(@PathVariable("id") String id) throws WorkFlowException {
        TemplateJsonEntity entity = templateJsonService.getInfo(id);
        List<TemplateJsonEntity> list = templateJsonService.getList(entity.getTemplateId());
        if (list.size() == 1) {
            return ActionResult.fail(MsgCode.WF071.get());
        }
        if (Objects.equals(entity.getState(), 1)) {
            return ActionResult.fail(MsgCode.WF072.get());
        }
        if (Objects.equals(entity.getState(), 2)) {
            return ActionResult.fail(MsgCode.WF073.get());
        }
        templateJsonService.delete(ImmutableList.of(id));
        return ActionResult.success(MsgCode.SU003.get());
    }

    /**
     * 上架下架
     *
     * @param id 主键
     * @param fo 参数
     */
    @Operation(summary = "上架下架")
    @PutMapping("/{id}/UpDownShelf")
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult updateStatus(@PathVariable("id") String id, @RequestBody UpDownModel fo) throws WorkFlowException {
        TemplateEntity entity = templateService.getInfo(id);
        if (ObjectUtil.equals(fo.getIsUp(), 0)) {
            entity.setStatus(1);
        } else {
            entity.setStatus(ObjectUtil.equals(fo.getIsHidden(), 0) ? 2 : 3);
        }
        templateService.updateById(entity);
        return ActionResult.success(MsgCode.SU005.get());
    }

    /**
     * 复制流程引擎
     *
     * @param id 主键
     * @return
     */
    @Operation(summary = "复制流程引擎")
    @PostMapping("/{id}/Actions/Copy")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult copy(@PathVariable("id") String id) throws WorkFlowException {
        TemplateEntity entity = templateService.getInfo(id);
        templateService.copy(entity);
        return ActionResult.success(MsgCode.SU007.get());
    }

    /**
     * 复制流程版本
     *
     * @param id 主键
     * @return
     */
    @Operation(summary = "复制流程版本")
    @PostMapping("/Info/{id}")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult copyVersion(@PathVariable("id") String id) throws WorkFlowException {
        String templateJsonId = RandomUtil.uuId();
        TemplateJsonEntity entity = templateJsonService.getInfo(id);
        templateJsonService.copy(entity, templateJsonId);
        return ActionResult.success(MsgCode.SU007.get(), templateJsonId);
    }

    /**
     * 流程保存或发布
     *
     * @return
     */
    @Operation(summary = "流程保存或发布")
    @PostMapping("/Save")
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult save(@RequestBody @Valid TemplateNodeUpFrom form) throws WorkFlowException {
        templateJsonService.save(form);
        return ActionResult.success(MsgCode.SU004.get());
    }

    /**
     * 导出
     *
     * @param id 主键
     */
    @Operation(summary = "导出")
    @GetMapping("/{id}/Actions/Export")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
    })
    public ActionResult<DownloadVO> export(@PathVariable("id") String id) throws WorkFlowException {
        TemplateExportModel model = templateService.export(id);
        DownloadVO downloadVO = serviceUtil.exportData(model);
        return ActionResult.success(downloadVO);
    }

    /**
     * 导入
     *
     * @param file 文件
     * @param type 类型
     */
    @Operation(summary = "导入")
    @PostMapping(value = "/Actions/Import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @SaCheckPermission(value = {"workFlow.flowEngine"})
    public ActionResult<String> importData(@RequestPart("file") MultipartFile file, @RequestParam("type") String type) throws WorkFlowException {
        //判断是否为.json结尾
        if (FileUtil.existsSuffix(file, ModuleTypeEnum.FLOW_FLOWENGINE.getTableName())) {
            return ActionResult.fail(MsgCode.IMP002.get());
        }
        //获取文件内容
        String fileContent = FileUtil.getFileContent(file);
        TemplateExportModel model = JsonUtil.getJsonToBean(fileContent, TemplateExportModel.class);
        if (ObjectUtil.isEmpty(model.getTemplate())) {
            return ActionResult.fail(MsgCode.IMP004.get());
        }
        templateService.importData(model, type);
        return ActionResult.success(MsgCode.IMP001.get());
    }

    /**
     * 委托可选全部流程
     *
     * @param pagination 分页参数
     */
    @Operation(summary = "委托可选全部流程")
    @GetMapping("/GetFlowAll")
    public ActionResult getFlowAll(TemplatePagination pagination) {
        List<TemplateEntity> list = templateService.getListAll(pagination, true);
        List<TemplatePageLisVO> voList = JsonUtil.getJsonToList(list, TemplatePageLisVO.class);
        PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
        return ActionResult.page(voList, paginationVO);
    }

    /**
     * 委托流程选择展示
     *
     * @param ids 版本主键集合
     */
    @Operation(summary = "委托流程选择展示")
    @PostMapping("/GetFlowList")
    public ActionResult getFlowList(@RequestBody List<String> ids) {
        List<TemplateEntity> list = templateService.getList(ids);
        List<FlowListModel> voList = new ArrayList<>();
        for (TemplateEntity templateEntity : list) {
            FlowListModel model = new FlowListModel();
            model.setId(templateEntity.getId());
            model.setFullName(templateEntity.getFullName());
            model.setEnCode(templateEntity.getEnCode());
            voList.add(model);
        }
        return ActionResult.success(voList);
    }

    /**
     * 子流程表单信息
     *
     * @param id 版本主键
     */
    @Operation(summary = "子流程表单信息")
    @GetMapping("/{id}/FormInfo")
    public ActionResult formInfo(@PathVariable("id") String id) throws WorkFlowException {
        VisualdevEntity formInfo = templateJsonService.getFormInfo(id);
        return ActionResult.success(formInfo);
    }

    /**
     * 根据表单主键获取流程
     *
     * @param formId 表单主键
     */
    @Operation(summary = "根据表单主键获取流程")
    @GetMapping("/{formId}/FlowList")
    public ActionResult getByFormId(@PathVariable("formId") String formId, Boolean start) {
        FlowByFormModel model = templateService.getFlowByFormId(formId, start);
        return ActionResult.success(model);
    }

    /**
     * 子流程可发起人员
     *
     * @param id         版本主键
     * @param pagination 分页参数
     */
    @Operation(summary = "子流程可发起人员")
    @GetMapping("/{id}/SubFlowUserList")
    public ActionResult getSubFlowUserList(@PathVariable("id") String id, TemplatePagination pagination) throws WorkFlowException {
        List<UserEntity> list = templateService.getSubFlowUserList(id, pagination);
        List<CandidateUserVo> voList = new ArrayList<>();
        List<String> userIdList = list.stream().map(UserEntity::getId).collect(Collectors.toList());
        Map<String, List<UserRelationEntity>> userMap = serviceUtil.getListByUserIdAll(userIdList).stream()
                .filter(t -> PermissionConst.ORGANIZE.equals(t.getObjectType())).collect(Collectors.groupingBy(UserRelationEntity::getUserId));
        for (UserEntity user : list) {
            CandidateUserVo vo = JsonUtil.getJsonToBean(user, CandidateUserVo.class);
            vo.setFullName(user.getRealName() + "/" + user.getAccount());
            vo.setHeadIcon(UploaderUtil.uploaderImg(user.getHeadIcon()));
            List<UserRelationEntity> listByUserId = userMap.get(user.getId()) != null ? userMap.get(user.getId()) : new ArrayList<>();
            StringJoiner joiner = new StringJoiner(",");
            for (UserRelationEntity relation : listByUserId) {
                List<OrganizeEntity> organizeId = serviceUtil.getOrganizeId(relation.getObjectId());
                if (!organizeId.isEmpty()) {
                    String organizeName = organizeId.stream().map(OrganizeEntity::getFullName).collect(Collectors.joining("/"));
                    joiner.add(organizeName);
                }
            }
            vo.setOrganize(joiner.toString());
            voList.add(vo);
        }
        PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
        return ActionResult.page(voList, paginationVO);
    }

    /**
     * 常用流程
     *
     * @param id 版本主键
     */
    @Operation(summary = "常用流程")
    @PostMapping("/SetCommonFlow/{id}")
    public ActionResult SetCommonFlow(@PathVariable("id") String id) {
        int flag = commonService.setCommonFLow(id);
        if (flag == 2) {
            return ActionResult.success(MsgCode.SU021.get());
        }
        return ActionResult.success(MsgCode.SU016.get());
    }

    /**
     * 根据模板主键获取表单
     *
     * @param templateId 流程模板主键
     */
    @Operation(summary = "根据模板主键获取表单")
    @GetMapping("/StartForm/{templateId}")
    public ActionResult getFormByTemplateId(@PathVariable("templateId") String templateId) throws WorkFlowException {
        return ActionResult.success(templateService.getFormByTemplateId(templateId));
    }

    /**
     * 根据模板主键获取表单主键和流程版本主键
     *
     * @param templateId 流程模板主键
     */
    @Operation(summary = "根据模板主键获取表单主键和流程版本主键")
    @GetMapping("/StartFormId/{templateId}")
    public ActionResult getFormIdAndFlowIdByTemplateId(@PathVariable("templateId") String templateId) throws WorkFlowException {
        return ActionResult.success(templateService.getFormIdAndFlowId(templateId));
    }

    @Override
    public FlowByFormModel getFlowByFormId(String formId, Boolean start) {
        return templateService.getFlowByFormId(formId, start);
    }

    @Override
    public String getFormByFlowId(String templateId) {
        String formId = "";
        try {
            VisualdevEntity entity = templateService.getFormByTemplateId(templateId);
            if (null == entity) {
                throw new WorkFlowException(MsgCode.VS412.get());
            }
            formId = entity.getId();
        } catch (Exception e) {
            log.error("流程获取表单失败: {}", e.getMessage());
        }
        return formId;
    }

    @Override
    public List<String> getFlowIdsByTemplateId(String templateId) {
        List<TemplateJsonEntity> list = templateJsonService.getList(templateId);
        return list.stream().map(TemplateJsonEntity::getId).distinct().collect(Collectors.toList());
    }

    @Override
    public List<TemplateJsonEntity> getFlowIdsByTemplate(String templateId) {
        return templateJsonService.getList(templateId);
    }

    @Override
    public List<TemplateEntity> getListByFlowIds(List<String> flowId) {
        return templateService.getList(flowId);
    }

    @Override
    public List<TemplateTreeListVo> treeListWithPower() {
        return templateService.treeListWithPower();
    }

    @Override
    public FlowWorkListVO flowWork(String fromId) {
        return operatorService.flowWork(fromId);
    }

    @Override
    public boolean flowWork(WorkHandoverModel workHandoverModel) {
        return operatorService.flowWork(workHandoverModel);
    }

    @Override
    public List<String> getFormList() {
        return templateService.getFormList();
    }

    @Override
    public String getTemplateByVersionId(String flowId) {
        String templateId = "";
        TemplateJsonEntity byId = templateJsonService.getById(flowId);
        if (byId != null) {
            templateId = byId.getTemplateId();
        }
        return templateId;
    }

    @Override
    public Map<String, String> getFlowFormMap() {
        return templateService.getFlowFormMap();
    }
}

