package cn.stylefeng.team.project.modular.filing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.team.project.modular.filing.entity.BusinessFlow;
import cn.stylefeng.team.project.modular.filing.exceptions.BusinessFlowExceptionEnum;
import cn.stylefeng.team.project.modular.filing.mapper.BusinessFlowMapper;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.add.BusinessFlowAddRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.del.BusinessFlowBatchDelRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.del.BusinessFlowDelRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.edit.BusinessFlowEditRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.edit.BusinessFlowUpdateStatusRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.query.BusinessFlowDetailRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.query.BusinessFlowListRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.query.BusinessFlowPageRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.response.BusinessFlowDetailResponse;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.response.BusinessFlowListResponse;
import cn.stylefeng.team.project.modular.filing.pojo.businessFlow.response.BusinessFlowPageResponse;
import cn.stylefeng.team.project.modular.filing.service.BusinessFlowService;
import cn.stylefeng.workflow.api.entity.design.Model;
import cn.stylefeng.workflow.design.modular.factory.BusinessModelFactory;
import cn.stylefeng.workflow.design.modular.pojo.request.ModelRequest;
import cn.stylefeng.workflow.design.modular.service.ModelService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class BusinessFlowServiceImpl extends ServiceImpl<BusinessFlowMapper, BusinessFlow> implements BusinessFlowService {

    @Resource
    private ModelService modelService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long add(BusinessFlowAddRequest businessFlowAddRequest) {

        ModelRequest modelRequest = BusinessModelFactory.createBusinessModel(businessFlowAddRequest.getModelName());
        Model model = modelService.add(modelRequest);

        BusinessFlow businessFlow = new BusinessFlow();
        businessFlow.setBusinessId(businessFlowAddRequest.getBusinessId());
        businessFlow.setFlowModelId(model.getModelId());
        businessFlow.setEnableFlag(YesOrNotEnum.N.getCode());
        this.save(businessFlow);

        return businessFlow.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(BusinessFlowDelRequest businessFlowDelRequest) {

        BusinessFlow businessFlow = this.queryBusinessFlow(businessFlowDelRequest.getId());
        this.removeById(businessFlow.getId());

        ModelRequest modelRequest = new ModelRequest();
        modelRequest.setModelId(businessFlow.getFlowModelId());
        modelService.del(modelRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(BusinessFlowBatchDelRequest businessFlowBatchDelRequest) {
        for (Long id : businessFlowBatchDelRequest.getBatchDeleteIdList()) {
            BusinessFlowDelRequest businessFlowRequest = new BusinessFlowDelRequest();
            businessFlowRequest.setId(id);
            this.del(businessFlowRequest);
        }
    }

    @Override
    public void edit(BusinessFlowEditRequest businessFlowEditRequest) {

        BusinessFlow build = this.queryBusinessFlow(businessFlowEditRequest.getId());

        Long flowModelId = build.getFlowModelId();

        LambdaUpdateWrapper<Model> modelLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        modelLambdaUpdateWrapper.eq(Model::getModelId, flowModelId);
        modelLambdaUpdateWrapper.set(Model::getModelName, businessFlowEditRequest.getModelName());
        modelLambdaUpdateWrapper.set(Model::getRemark, businessFlowEditRequest.getRemark());
        this.modelService.update(modelLambdaUpdateWrapper);
    }

    @Override
    public BusinessFlowDetailResponse detail(BusinessFlowDetailRequest businessFlowDetailRequest) {

        BusinessFlow businessFlow = this.queryBusinessFlow(businessFlowDetailRequest.getId());
        BusinessFlowDetailResponse businessFlowDetailResponse = BeanUtil.copyProperties(businessFlow, BusinessFlowDetailResponse.class);

        Model model = modelService.getById(businessFlow.getFlowModelId());
        businessFlowDetailResponse.setModelName(model.getModelName());
        businessFlowDetailResponse.setRemark(model.getRemark());

        return businessFlowDetailResponse;
    }

    @Override
    public List<BusinessFlowListResponse> findList(BusinessFlowListRequest businessFlowListRequest) {
        LambdaQueryWrapper<BusinessFlow> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BusinessFlow::getBusinessId, businessFlowListRequest.getBusinessId());
        List<BusinessFlow> list = this.list(wrapper);
        if (ObjectUtil.isEmpty(list)) {
            return new ArrayList<>();
        }

        List<BusinessFlowListResponse> businessFlowListResponses = BeanUtil.copyToList(list, BusinessFlowListResponse.class);

        Set<Long> modelIdList = businessFlowListResponses.stream().map(BusinessFlowListResponse::getFlowModelId).collect(Collectors.toSet());
        List<Model> modelList = modelService.listByIds(modelIdList);

        for (BusinessFlowListResponse businessFlowListResponse : businessFlowListResponses) {
            for (Model model : modelList) {
                if (businessFlowListResponse.getFlowModelId().equals(model.getModelId())) {
                    businessFlowListResponse.setModelName(model.getModelName());
                    businessFlowListResponse.setRemark(model.getRemark());
                    businessFlowListResponse.setModelIconType(model.getModelIconType());
                    businessFlowListResponse.setModelIcon(model.getModelIcon());
                    businessFlowListResponse.setModelIconFileId(model.getModelIconFileId());
                    businessFlowListResponse.setLatestDefinitionId(model.getLatestDefinitionId());
                }
            }
        }

        return businessFlowListResponses;
    }

    @Override
    public PageResult<BusinessFlowPageResponse> findPage(BusinessFlowPageRequest businessFlowPageRequest) {
        Page<BusinessFlow> page = PageFactory.defaultPage();

        LambdaQueryWrapper<BusinessFlow> wrapper = new LambdaQueryWrapper<>();


        Page<BusinessFlow> pageResult = this.page(page, wrapper);
        List<BusinessFlow> resultRecords = pageResult.getRecords();
        if (ObjectUtil.isEmpty(resultRecords)) {
            return PageResultFactory.createPageResult(page, new ArrayList<>());
        }

        List<BusinessFlowPageResponse> businessFlowPageResponses = BeanUtil.copyToList(resultRecords, BusinessFlowPageResponse.class);
        return PageResultFactory.createPageResult(pageResult, businessFlowPageResponses);
    }

    @Override
    public BusinessFlowDetailResponse customDetail(BusinessFlowDetailRequest businessFlowDetailRequest) {
        return this.getBaseMapper().customDetail(businessFlowDetailRequest);
    }

    @Override
    public List<BusinessFlowListResponse> customList(BusinessFlowListRequest businessFlowListRequest) {
        return this.getBaseMapper().customList(businessFlowListRequest);
    }

    @Override
    public PageResult<BusinessFlowPageResponse> customPage(BusinessFlowPageRequest businessFlowPageRequest) {
        Page<BusinessFlowPageResponse> page = PageFactory.defaultPage();

        List<BusinessFlowPageResponse> businessFlowPageResponses = this.getBaseMapper().customPage(page, businessFlowPageRequest);
        page.setRecords(businessFlowPageResponses);

        return PageResultFactory.createPageResult(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(BusinessFlowUpdateStatusRequest businessFlowUpdateStatusRequest) {

        if (YesOrNotEnum.N.getCode().equalsIgnoreCase(businessFlowUpdateStatusRequest.getEnableFlag())) {
            LambdaUpdateWrapper<BusinessFlow> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(BusinessFlow::getId, businessFlowUpdateStatusRequest.getId());
            updateWrapper.set(BusinessFlow::getEnableFlag, YesOrNotEnum.N.getCode());
            this.update(updateWrapper);
            return;
        }

        LambdaQueryWrapper<BusinessFlow> wrapper = new LambdaQueryWrapper<>();
        List<BusinessFlow> list = this.list(wrapper);
        for (BusinessFlow businessFlow : list) {
            if (businessFlow.getId().equals(businessFlowUpdateStatusRequest.getId())) {
                continue;
            }
            businessFlow.setEnableFlag(YesOrNotEnum.N.getCode());
        }
        this.updateBatchById(list);

        LambdaUpdateWrapper<BusinessFlow> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BusinessFlow::getId, businessFlowUpdateStatusRequest.getId());
        updateWrapper.set(BusinessFlow::getEnableFlag, YesOrNotEnum.Y.getCode());
        this.update(updateWrapper);
    }

    @Override
    public Map<Long, Integer> statBusinessFlowNumber(Set<Long> businessIds) {
        HashMap<Long, Integer> resultMap = new HashMap<>();

        if (ObjectUtil.isEmpty(businessIds)) {
            return resultMap;
        }

        LambdaQueryWrapper<BusinessFlow> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(BusinessFlow::getBusinessId, businessIds);
        wrapper.select(BusinessFlow::getBusinessId, BusinessFlow::getId);
        List<BusinessFlow> metaDictList = this.list(wrapper);
        if (ObjectUtil.isEmpty(metaDictList)) {
            return resultMap;
        }

        return metaDictList.stream().collect(Collectors.groupingBy(BusinessFlow::getBusinessId, Collectors.summingInt(i -> 1)));
    }

    @Override
    public BusinessFlow queryBusinessLinkFlow(Long businessId) {
        LambdaQueryWrapper<BusinessFlow> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BusinessFlow::getBusinessId, businessId);
        queryWrapper.eq(BusinessFlow::getEnableFlag, YesOrNotEnum.Y.getCode());
        List<BusinessFlow> businessFlowList = this.list(queryWrapper);
        if (ObjectUtil.isEmpty(businessFlowList)) {
            return null;
        }

        if (businessFlowList.size() > 1) {
            log.warn("业务id：" + businessId + "下有多个流程，请检查");
        }

        return businessFlowList.get(0);
    }

    private BusinessFlow queryBusinessFlow(Long id) {
        BusinessFlow businessFlow = this.getById(id);
        if (ObjectUtil.isEmpty(businessFlow)) {
            throw new ServiceException(BusinessFlowExceptionEnum.BUSINESS_FLOW_NOT_EXISTED);
        }
        return businessFlow;
    }
}