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.file.api.pojo.request.SysFileInfoRequest;
import cn.stylefeng.roses.kernel.file.api.pojo.response.SysFileInfoResponse;
import cn.stylefeng.roses.kernel.file.modular.entity.SysFileInfo;
import cn.stylefeng.roses.kernel.file.modular.factory.FileInfoFactory;
import cn.stylefeng.roses.kernel.file.modular.service.SysFileInfoService;
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.BusinessExcel;
import cn.stylefeng.team.project.modular.filing.exceptions.BusinessExcelExceptionEnum;
import cn.stylefeng.team.project.modular.filing.mapper.BusinessExcelMapper;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.add.BusinessExcelAddRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.del.BusinessExcelBatchDelRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.del.BusinessExcelDelRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.edit.BusinessExcelEditRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.edit.BusinessExcelUpdateStatusRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.edit.ExcelContentUpdateRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.query.BusinessExcelDetailRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.query.BusinessExcelListRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.query.BusinessExcelPageRequest;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.response.BusinessExcelDetailResponse;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.response.BusinessExcelListResponse;
import cn.stylefeng.team.project.modular.filing.pojo.businessExcel.response.BusinessExcelPageResponse;
import cn.stylefeng.team.project.modular.filing.service.BusinessExcelService;
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 org.springframework.web.multipart.MultipartFile;

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

@Service
public class BusinessExcelServiceImpl extends ServiceImpl<BusinessExcelMapper, BusinessExcel> implements BusinessExcelService {

    @Resource
    private SysFileInfoService sysFileInfoService;

    @Override
    public Long add(BusinessExcelAddRequest businessExcelAddRequest) {
        BusinessExcel businessExcel = new BusinessExcel();
        BeanUtil.copyProperties(businessExcelAddRequest, businessExcel);

        businessExcel.setEnableFlag(YesOrNotEnum.N.getCode());

        this.save(businessExcel);
        return businessExcel.getId();
    }

    @Override
    public void del(BusinessExcelDelRequest businessExcelDelRequest) {
        BusinessExcel businessExcel = this.queryBusinessExcel(businessExcelDelRequest.getId());
        this.removeById(businessExcel.getId());

        if (ObjectUtil.isNotEmpty(businessExcel.getExcelFileId())) {
            this.sysFileInfoService.removeFile(businessExcel.getExcelFileId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(BusinessExcelBatchDelRequest businessExcelBatchDelRequest) {
        for (Long excelInfoId : businessExcelBatchDelRequest.getBatchDeleteIdList()) {
            BusinessExcelDelRequest businessExcelDelRequest = new BusinessExcelDelRequest();
            businessExcelDelRequest.setId(excelInfoId);
            this.del(businessExcelDelRequest);
        }
    }

    @Override
    public void edit(BusinessExcelEditRequest businessExcelEditRequest) {

        BusinessExcel businessExcel = this.queryBusinessExcel(businessExcelEditRequest.getId());
        BeanUtil.copyProperties(businessExcelEditRequest, businessExcel);
        this.updateById(businessExcel);
    }

    @Override
    public BusinessExcelDetailResponse detail(BusinessExcelDetailRequest businessExcelDetailRequest) {
        BusinessExcel businessExcel = this.queryBusinessExcel(businessExcelDetailRequest.getId());
        return BeanUtil.copyProperties(businessExcel, BusinessExcelDetailResponse.class);
    }

    @Override
    public List<BusinessExcelListResponse> findList(BusinessExcelListRequest businessExcelListRequest) {
        LambdaQueryWrapper<BusinessExcel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BusinessExcel::getBusinessId, businessExcelListRequest.getBusinessId());
        List<BusinessExcel> list = this.list(wrapper);

        return BeanUtil.copyToList(list, BusinessExcelListResponse.class);
    }

    @Override
    public PageResult<BusinessExcelPageResponse> findPage(BusinessExcelPageRequest businessExcelPageRequest) {
        Page<BusinessExcel> page = PageFactory.defaultPage();

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


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

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

    @Override
    public BusinessExcelDetailResponse customDetail(BusinessExcelDetailRequest businessExcelDetailRequest) {
        return this.getBaseMapper().customDetail(businessExcelDetailRequest);
    }

    @Override
    public List<BusinessExcelListResponse> customList(BusinessExcelListRequest businessExcelListRequest) {
        return this.getBaseMapper().customList(businessExcelListRequest);
    }

    @Override
    public PageResult<BusinessExcelPageResponse> customPage(BusinessExcelPageRequest businessExcelPageRequest) {
        Page<BusinessExcelPageResponse> page = PageFactory.defaultPage();

        List<BusinessExcelPageResponse> businessExcelPageResponses = this.getBaseMapper().customPage(page, businessExcelPageRequest);
        page.setRecords(businessExcelPageResponses);

        return PageResultFactory.createPageResult(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(BusinessExcelUpdateStatusRequest businessExcelUpdateStatusRequest) {

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

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

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

    @Override
    public void updateExcelContent(MultipartFile file, ExcelContentUpdateRequest excelContentUpdateRequest) {

        BusinessExcel businessExcel = this.queryBusinessExcel(excelContentUpdateRequest.getId());
        Long excelFileId = businessExcel.getExcelFileId();

        if (ObjectUtil.isEmpty(excelFileId)) {

            SysFileInfoRequest sysFileInfoRequest = new SysFileInfoRequest();
            sysFileInfoRequest.setSecretFlag(YesOrNotEnum.Y.getCode());
            SysFileInfo sysFileInfo = FileInfoFactory.createSysFileInfo(file, sysFileInfoRequest);

            this.sysFileInfoService.storageFile(file, sysFileInfo);

            this.sysFileInfoService.save(sysFileInfo);

            businessExcel.setExcelFileId(sysFileInfo.getFileId());
            this.updateById(businessExcel);

            return;
        }

        SysFileInfo sysFileInfo = this.sysFileInfoService.getById(excelFileId);
        this.sysFileInfoService.storageFile(file, sysFileInfo);
    }

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

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

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

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

    @Override
    public void cleanAndSaveExcel(Long businessId, Long excelFileId) {

        SysFileInfoResponse file = this.sysFileInfoService.getFileInfoWithoutContent(excelFileId);

        LambdaQueryWrapper<BusinessExcel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BusinessExcel::getBusinessId, businessId);
        this.remove(wrapper);

        BusinessExcel businessExcel = new BusinessExcel();
        businessExcel.setBusinessId(businessId);
        businessExcel.setExcelName(file.getFileOriginName());
        businessExcel.setExcelFileId(excelFileId);
        businessExcel.setEnableFlag(YesOrNotEnum.Y.getCode());
        this.save(businessExcel);
    }

    private BusinessExcel queryBusinessExcel(Long id) {
        BusinessExcel businessExcel = this.getById(id);
        if (ObjectUtil.isEmpty(businessExcel)) {
            throw new ServiceException(BusinessExcelExceptionEnum.BUSINESS_EXCEL_NOT_EXISTED);
        }
        return businessExcel;
    }
}