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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
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.entity.BaseEntity;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.sys.api.pojo.menu.BusinessViewDTO;
import cn.stylefeng.roses.kernel.sys.api.pojo.menu.ProjectBusinessDTO;
import cn.stylefeng.team.form.api.FormModelServiceApi;
import cn.stylefeng.team.form.api.entity.FormModel;
import cn.stylefeng.team.meta.api.MetaModelServiceApi;
import cn.stylefeng.team.meta.api.UserDictServiceApi;
import cn.stylefeng.team.meta.api.entity.MetaModel;
import cn.stylefeng.team.project.api.entity.Business;
import cn.stylefeng.team.project.api.entity.BusinessCategory;
import cn.stylefeng.team.project.api.entity.BusinessPermission;
import cn.stylefeng.team.project.modular.business.enums.BusinessExceptionEnum;
import cn.stylefeng.team.project.modular.business.factory.BusinessTreeFactory;
import cn.stylefeng.team.project.modular.business.mapper.BusinessMapper;
import cn.stylefeng.team.project.modular.business.pojo.request.BusinessRequest;
import cn.stylefeng.team.project.modular.business.pojo.response.BusinessVo;
import cn.stylefeng.team.project.modular.business.service.BusinessCategoryService;
import cn.stylefeng.team.project.modular.business.service.BusinessPermissionService;
import cn.stylefeng.team.project.modular.business.service.BusinessService;
import cn.stylefeng.team.project.modular.businessrender.pojo.response.BusinessModelFormViewResponse;
import cn.stylefeng.team.view.api.ViewApi;
import cn.stylefeng.team.view.api.entity.View;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> implements BusinessService {

    @Resource
    private BusinessCategoryService businessCategoryService;

    @Resource
    private MetaModelServiceApi metaModelServiceApi;

    @Resource
    private FormModelServiceApi formModelServiceApi;

    @Resource
    private ViewApi viewApi;

    @Resource
    private UserDictServiceApi userDictServiceApi;

    @Resource
    private BusinessPermissionService businessPermissionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(BusinessRequest businessRequest) {

        Business business = new Business();
        BeanUtil.copyProperties(businessRequest, business);
        this.save(business);

        businessPermissionService.addBusinessFillingPermission(business.getBusinessId(), businessRequest.getBusinessPermissionList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(BusinessRequest businessRequest) {
        this.getBaseMapper().batchDeleteBusinessInfo(ListUtil.of(businessRequest.getBusinessId()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(BusinessRequest businessRequest) {
        this.getBaseMapper().batchDeleteBusinessInfo(businessRequest.getBatchDeleteIdList());
    }

    @Override
    public void edit(BusinessRequest businessRequest) {

        businessRequest.setSystemCode(null);
        businessRequest.setSystemCodeShow(null);

        Business business = this.queryBusiness(businessRequest);
        BeanUtil.copyProperties(businessRequest, business);
        this.updateById(business);

        this.businessPermissionService.removeBusinessFilingPermission(business.getBusinessId());
        this.businessPermissionService.addBusinessFillingPermission(business.getBusinessId(), businessRequest.getBusinessPermissionList());
    }

    @Override
    public Business detail(BusinessRequest businessRequest) {

        Business business = this.queryBusiness(businessRequest);

        List<BusinessPermission> businessPermissionList = this.businessPermissionService.queryBusinessFilingPermissionList(business.getBusinessId());
        this.businessPermissionService.processPermissionName(businessPermissionList);
        business.setBusinessPermissionList(businessPermissionList);

        return business;
    }

    @Override
    public PageResult<BusinessVo> findPage(BusinessRequest businessRequest) {
        LambdaQueryWrapper<Business> wrapper = createWrapper(businessRequest);

        wrapper.select(Business::getBusinessId, Business::getBusinessName, Business::getBusinessIcon, Business::getBusinessIconFileId, Business::getBusinessIconType, Business::getBusinessCode,
                Business::getSystemCodeShow, Business::getFldSort, BaseEntity::getCreateTime);

        Page<Business> pageList = this.page(PageFactory.defaultPage(), wrapper);

        List<BusinessVo> businessVos = this.convertToVo(pageList.getRecords());

        return PageResultFactory.createPageResult(businessVos, pageList.getTotal(), Convert.toInt(pageList.getSize()), Convert.toInt(pageList.getCurrent()));
    }

    @Override
    public List<Business> getCategoryBusinessList(List<Long> categoryId, String searchText) {

        BusinessRequest businessRequest = new BusinessRequest();
        businessRequest.setSearchText(searchText);

        LambdaQueryWrapper<Business> businessLambdaQueryWrapper = this.createWrapper(businessRequest);
        businessLambdaQueryWrapper.in(Business::getBusinessCategoryId, categoryId);
        businessLambdaQueryWrapper.select(Business::getBusinessName, Business::getBusinessId, Business::getBusinessCategoryId);
        return this.list(businessLambdaQueryWrapper);
    }

    @Override
    public BusinessModelFormViewResponse getBusinessModelFormView(BusinessRequest businessRequest) {

        BusinessModelFormViewResponse businessModelFormViewResponse = new BusinessModelFormViewResponse();

        List<MetaModel> businessMetaModelList = metaModelServiceApi.getBusinessMetaModelList(businessRequest.getBusinessId(), null);
        businessModelFormViewResponse.setMetaModelList(businessMetaModelList);

        List<FormModel> formModelList = formModelServiceApi.getBusinessFormModelList(businessRequest.getBusinessId());
        businessModelFormViewResponse.setFormModelList(formModelList);

        List<View> viewList = viewApi.getBusinessViewList(businessRequest.getBusinessId());
        businessModelFormViewResponse.setViewList(viewList);

        return businessModelFormViewResponse;
    }

    @Override
    public List<Business> findList(BusinessRequest businessRequest) {
        LambdaQueryWrapper<Business> wrapper = this.createWrapper(businessRequest);
        return this.list(wrapper);
    }

    @Override
    public List<ProjectBusinessDTO> getProjectBusinessList() {

        List<BusinessCategory> totalBusinessCategory = businessCategoryService.getTotalBusinessCategory();

        LambdaQueryWrapper<Business> businessLambdaQueryWrapper = new LambdaQueryWrapper<>();
        businessLambdaQueryWrapper.select(Business::getBusinessCategoryId, Business::getBusinessId, Business::getBusinessName);
        List<Business> totalBusinessList = this.list(businessLambdaQueryWrapper);

        return BusinessTreeFactory.createBusinessTree(totalBusinessCategory, totalBusinessList);
    }

    @Override
    public List<BusinessViewDTO> getBusinessViewList(Long businessId) {

        if (businessId == null) {
            return new ArrayList<>();
        }

        List<View> viewList = viewApi.getViewListByBusinessId(businessId);
        if (ObjectUtil.isEmpty(viewList)) {
            return new ArrayList<>();
        }

        List<BusinessViewDTO> businessViewDTOS = new ArrayList<>();
        for (View view : viewList) {
            BusinessViewDTO businessViewDTO = new BusinessViewDTO();
            businessViewDTO.setViewId(view.getViewId());
            businessViewDTO.setViewName(view.getViewName());
            businessViewDTOS.add(businessViewDTO);
        }

        return businessViewDTOS;
    }

    @Override
    public String getBusinessName(Long businessId) {
        LambdaQueryWrapper<Business> businessLambdaQueryWrapper = new LambdaQueryWrapper<>();
        businessLambdaQueryWrapper.eq(Business::getBusinessId, businessId);
        businessLambdaQueryWrapper.select(Business::getBusinessName);
        Business business = this.getOne(businessLambdaQueryWrapper, false);
        if (business == null) {
            return "";
        }
        return business.getBusinessName();
    }

    private Business queryBusiness(BusinessRequest businessRequest) {
        Business business = this.getById(businessRequest.getBusinessId());
        if (ObjectUtil.isEmpty(business)) {
            throw new ServiceException(BusinessExceptionEnum.BUSINESS_NOT_EXISTED);
        }
        return business;
    }

    private LambdaQueryWrapper<Business> createWrapper(BusinessRequest businessRequest) {
        LambdaQueryWrapper<Business> queryWrapper = new LambdaQueryWrapper<>();

        String searchText = businessRequest.getSearchText();
        if (StrUtil.isNotBlank(searchText)) {
            queryWrapper.nested(i -> {
                i.like(Business::getBusinessName, searchText);
                i.or().like(Business::getBusinessCode, searchText);
                i.or().like(Business::getSystemCodeShow, searchText);
            });
        }

        Long businessCategoryId = businessRequest.getBusinessCategoryId();
        if (ObjectUtil.isNotEmpty(businessCategoryId)) {
            queryWrapper.eq(Business::getBusinessCategoryId, businessCategoryId);
        }

        queryWrapper.orderByAsc(Business::getFldSort);

        return queryWrapper;
    }

    private List<BusinessVo> convertToVo(List<Business> businessList) {
        ArrayList<BusinessVo> businessVoList = new ArrayList<>();

        if (ObjectUtil.isEmpty(businessList)) {
            return businessVoList;
        }

        Set<Long> businessIds = businessList.stream().map(Business::getBusinessId).collect(Collectors.toSet());

        Map<Long, Integer> modelNumber = this.metaModelServiceApi.statModelNumber(businessIds);

        Map<Long, Integer> formNumber = this.formModelServiceApi.statFormNumber(businessIds);

        Map<Long, Integer> dictNumber = this.userDictServiceApi.statDictNumber(businessIds);

        for (Business business : businessList) {
            BusinessVo businessVo = new BusinessVo();
            BeanUtil.copyProperties(business, businessVo);
            businessVo.setTableCount(modelNumber.get(business.getBusinessId()));
            businessVo.setFormCount(formNumber.get(business.getBusinessId()));
            businessVo.setDictCount(dictNumber.get(business.getBusinessId()));
            businessVoList.add(businessVo);
        }

        return businessVoList;
    }
}
