package com.ningdatech.carapi.industry.manage;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.basic.util.ValidUtil;
import com.ningdatech.carapi.common.aop.BuildChildrenRegionWrapper;
import com.ningdatech.carapi.common.constant.CommonConstant;
import com.ningdatech.carapi.common.helper.UserInfoHelper;
import com.ningdatech.carapi.common.util.ExcelDownUtil;
import com.ningdatech.carapi.common.util.ExcelExportStyle;
import com.ningdatech.carapi.datascope.aop.LambdaDataScope;
import com.ningdatech.carapi.datascope.contants.LambdaDataScopeTypeEnum;
import com.ningdatech.carapi.industry.entity.LabAcceptanceCertificate;
import com.ningdatech.carapi.industry.entity.LabAcceptanceCertificateChange;
import com.ningdatech.carapi.industry.enums.AddTypeEnum;
import com.ningdatech.carapi.industry.model.dto.LabAcceptanceCertificateExportDto;
import com.ningdatech.carapi.industry.model.dto.LabAcceptanceCertificateImportDto;
import com.ningdatech.carapi.industry.model.req.LabAcceptanceCertificateListReq;
import com.ningdatech.carapi.industry.model.req.LabAcceptanceCertificateReq;
import com.ningdatech.carapi.industry.model.req.LabWorkerCertificateAuditReq;
import com.ningdatech.carapi.industry.model.vo.LabAcceptanceCertificateChangeListVo;
import com.ningdatech.carapi.industry.model.vo.LabAcceptanceCertificateListVo;
import com.ningdatech.carapi.industry.service.ILabAcceptanceCertificateChangeService;
import com.ningdatech.carapi.industry.service.ILabAcceptanceCertificateService;
import com.ningdatech.carapi.sys.entity.Company;
import com.ningdatech.carapi.sys.event.ImportDataEvent;
import com.ningdatech.carapi.sys.helper.RegionsCacheHelper;
import com.ningdatech.carapi.sys.service.CompanyService;
import com.ningdatech.carapi.user.util.LoginUserUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * LabAcceptanceCertificateManage
 * </p>
 *
 * @author WendyYang
 * @since 14:35 2022/11/8
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class LabAcceptanceCertificateManage {

    private final ILabAcceptanceCertificateService labAcceptanceCertificateService;

    private final ILabAcceptanceCertificateChangeService labAcceptanceCertificateChangeService;
    private final RegionsCacheHelper regionsCacheHelper;
    private final CompanyService companyService;
    private final UserInfoHelper userInfoHelper;

    public PageVo<LabAcceptanceCertificateListVo> labAcceptanceCertificateList(LabAcceptanceCertificateListReq req) {
        LambdaQueryWrapper<LabAcceptanceCertificate> wrapper = Wrappers.lambdaQuery(LabAcceptanceCertificate.class);
        LabAcceptanceCertificateManage context = (LabAcceptanceCertificateManage) AopContext.currentProxy();
        context.build(wrapper,req);
        Page<LabAcceptanceCertificate> page = labAcceptanceCertificateService.page(req.page(),wrapper);
        if (0L == page.getTotal()) {
            return PageVo.empty();
        }
        List<LabAcceptanceCertificateListVo> result = page.getRecords().stream().map(w -> {
            LabAcceptanceCertificateListVo vo = BeanUtil.copyProperties(w, LabAcceptanceCertificateListVo.class);
            vo.setRegionName(regionsCacheHelper.getDisplayName(w.getRegionId()));
            vo.setValidDate(w.getValidDate());
            return vo;
        }).collect(Collectors.toList());
        return PageVo.of(result, page.getTotal());
    }
    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void build(LambdaQueryWrapper<LabAcceptanceCertificate> wrapper,LabAcceptanceCertificateListReq req) {
        wrapper.ge(Objects.nonNull(req.getStartDate()),LabAcceptanceCertificate::getConferDate,req.getStartDate())
               .le(Objects.nonNull(req.getEndDate()),LabAcceptanceCertificate::getConferDate,req.getEndDate())
               .like(StringUtils.isNotBlank(req.getCompanyName()),LabAcceptanceCertificate::getCompanyName,req.getCompanyName())
               .orderByDesc(LabAcceptanceCertificate::getConferDate);
    }

    //=======================================================导出========================================================

    @EventListener(condition = "event.getTemplate() == T(com.ningdatech.carapi.sys.entity.enumeration.ImportTemplateEnum).LAB_ACCEPTANCE_CERTIFICATE")
    public void importDataListener(ImportDataEvent event) throws IOException {
        MultipartFile file = (MultipartFile) event.getSource();
        EasyExcel.read(file.getInputStream(), LabAcceptanceCertificateImportDto.class,
                new ReadListener<LabAcceptanceCertificateImportDto>() {

                    final List<LabAcceptanceCertificateImportDto> insert = new ArrayList<>();

                    @Override
                    public void invoke(LabAcceptanceCertificateImportDto data, AnalysisContext context) {
                        String s = ValidUtil.validFast(data);
                        Assert.isTrue(StrUtil.isBlank(s), s);
                        insert.add(data);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        log.info("所有数据读取完成:{}", insert.size());
                        importDataSave(insert);
                    }
                }).sheet(0).doRead();
    }

    private void importDataSave(List<LabAcceptanceCertificateImportDto> records) {
        Long userId = LoginUserUtil.getUserId();
        LocalDateTime now = LocalDateTime.now();
        List<String> companyNames = CollUtils.fieldList(records, LabAcceptanceCertificateImportDto::getCompanyName);
        List<Company> companies = companyService.listCompanyByCompanyNames(companyNames);
        Map<String, Company> companyMap = CollUtils.listToMap(companies, Company::getName);
        List<LabAcceptanceCertificate> list = new ArrayList<>();
        records.forEach(w -> {
            Company company = companyMap.get(w.getCompanyName());
            if (company == null) {
                return;
            }
            LabAcceptanceCertificate certificate = new LabAcceptanceCertificate();
            certificate.setCertificateNo(w.getCertificateNo());
            certificate.setRemark(w.getRemark());
            certificate.setRegionId(company.getRegionId());
            certificate.setValidDate(NdDateUtils.date2LocalDate(w.getValidDate()));
            certificate.setConferDate(NdDateUtils.date2LocalDate(w.getConferDate()));
            certificate.setConferOrg(w.getConferOrg());
            certificate.setCompanyName(company.getName());
            certificate.setCompanyId(company.getId());
            certificate.setCreateBy(userId);
            certificate.setCreateOn(now);
            certificate.setUpdateBy(userId);
            certificate.setUpdateOn(now);
            list.add(certificate);
        });
        labAcceptanceCertificateService.saveBatch(list);
    }

    //==================================================================================================================

    public void exportLabAcceptanceCertificate(HttpServletResponse response, LabAcceptanceCertificateListReq req) {
        req.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        PageVo<LabAcceptanceCertificateListVo> page = labAcceptanceCertificateList(req);
        List<LabAcceptanceCertificateExportDto> collect = page.getRecords().stream().map(w -> {
            LabAcceptanceCertificateExportDto dto = BeanUtil.copyProperties(w, LabAcceptanceCertificateExportDto.class);
            dto.setStandard(w.getStandard());
            dto.setTestItem(w.getTestItem());
            String conferDateStr = NdDateUtils.format(w.getConferDate(), NdDateUtils.DEFAULT_DATE_FORMAT);
            dto.setConferDate(conferDateStr);
            String validDateStr= NdDateUtils.format(w.getValidDate(), NdDateUtils.DEFAULT_DATE_FORMAT);
            dto.setValidDate(validDateStr);
            return dto;
        }).collect(Collectors.toList());
        String fileName = "实验室验收合格证";
        ExcelDownUtil.setFileName(fileName, response);
        // 数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), LabAcceptanceCertificateExportDto.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void saveOrUpdate(LabAcceptanceCertificateReq req) {
        Long userId = LoginUserUtil.getUserId();
        Integer addType = req.getAddType();
        // 说明是新增证书
        if (AddTypeEnum.NEW.getCode().equals(addType)) {
            LabAcceptanceCertificate labAcceptanceCertificate = new LabAcceptanceCertificate();
            if (Objects.nonNull(req.getId())){
                // 说明为编辑
                labAcceptanceCertificate.setId(req.getId());
            }
            labAcceptanceCertificate.setRegionId(req.getRegionId());
            labAcceptanceCertificate.setCompanyId(req.getCompanyId());
            labAcceptanceCertificate.setCompanyName(req.getCompanyName());
            labAcceptanceCertificate.setRecordItem(req.getRecordItem());
            labAcceptanceCertificate.setCertificateNo(req.getCertificateNo());
            labAcceptanceCertificate.setConferDate(req.getConferDate());
            labAcceptanceCertificate.setStandard(req.getStandard());
            labAcceptanceCertificate.setTestItem(req.getTestItem());
            labAcceptanceCertificate.setRemark(req.getRemark());
            labAcceptanceCertificate.setConferOrg(req.getConferOrg());

            labAcceptanceCertificate.setCreateOn(LocalDateTime.now());
            labAcceptanceCertificate.setCreateBy(userId);
            labAcceptanceCertificate.setUpdateOn(LocalDateTime.now());
            labAcceptanceCertificate.setUpdateBy(userId);

            labAcceptanceCertificateService.saveOrUpdate(labAcceptanceCertificate);
        } else if (AddTypeEnum.REPLACE.getCode().equals(req.getAddType())) {
            // 说明为换证
            LabAcceptanceCertificateChange labAcceptanceCertificateChange = new LabAcceptanceCertificateChange();
            if (Objects.nonNull(req.getId())){
                // 说明为编辑
                labAcceptanceCertificateChange.setId(req.getId());
            }
            String applicationItem = req.getApplicationItem();
            String applicationReason = req.getApplicationReason();
            if (Objects.isNull(applicationItem) || Objects.isNull(applicationReason)){
                throw new BizException("申请事项和申请原因不能为空!");
            }
            labAcceptanceCertificateChange.setCompanyName(req.getCompanyName());
            labAcceptanceCertificateChange.setRegionId(req.getRegionId());
            labAcceptanceCertificateChange.setCompanyId(req.getCompanyId());
            labAcceptanceCertificateChange.setCertificateNo(req.getCertificateNo());
            labAcceptanceCertificateChange.setRecordItem(req.getRecordItem());
            labAcceptanceCertificateChange.setReplacementTime(req.getReplaceDate());
            labAcceptanceCertificateChange.setConferOrg(req.getConferOrg());
            labAcceptanceCertificateChange.setRemark(req.getRemark());
            labAcceptanceCertificateChange.setApplicationItem(req.getApplicationItem());
            labAcceptanceCertificateChange.setApplicationReason(req.getApplicationReason());
            labAcceptanceCertificateChange.setTestItem(req.getTestItem());
            labAcceptanceCertificateChange.setValidDate(req.getValidDate());
            labAcceptanceCertificateChange.setStandard(req.getStandard());

            labAcceptanceCertificateChange.setCreateOn(LocalDateTime.now());
            labAcceptanceCertificateChange.setCreateBy(userId);
            labAcceptanceCertificateChange.setUpdateOn(LocalDateTime.now());
            labAcceptanceCertificateChange.setUpdateBy(userId);
            labAcceptanceCertificateChangeService.saveOrUpdate(labAcceptanceCertificateChange);
        }
    }

    public PageVo<LabAcceptanceCertificateChangeListVo> changeList(LabAcceptanceCertificateListReq req) {
        LambdaQueryWrapper<LabAcceptanceCertificateChange> wrapper = Wrappers.lambdaQuery(LabAcceptanceCertificateChange.class);
        LabAcceptanceCertificateManage context = (LabAcceptanceCertificateManage) AopContext.currentProxy();
        context.buildChangeListQuery(wrapper,req);
        Page<LabAcceptanceCertificateChange> page = labAcceptanceCertificateChangeService.page(req.page(), wrapper);
        if (CollUtil.isEmpty(page.getRecords())){
            return PageVo.empty();
        }
        List<LabAcceptanceCertificateChangeListVo> data = CollUtils.convert(page.getRecords(), w -> {
            LabAcceptanceCertificateChangeListVo resVo = BeanUtil.copyProperties(w, LabAcceptanceCertificateChangeListVo.class);
            resVo.setRegionName(regionsCacheHelper.getDisplayName(w.getRegionId()));
            resVo.setReplaceDate(w.getReplacementTime());
            return resVo;
        });

        return PageVo.of(data,page.getTotal());
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildChangeListQuery(LambdaQueryWrapper<LabAcceptanceCertificateChange> wrapper, LabAcceptanceCertificateListReq req) {
        wrapper.like(StrUtil.isNotBlank(req.getCompanyName()), LabAcceptanceCertificateChange::getCompanyName, req.getCompanyName())
                .ge(Objects.nonNull(req.getStartDate()),LabAcceptanceCertificateChange::getReplacementTime,req.getStartDate())
                .le(Objects.nonNull(req.getEndDate()),LabAcceptanceCertificateChange::getReplacementTime,req.getEndDate())
                .orderByDesc(LabAcceptanceCertificateChange::getUpdateOn);
    }

    public Boolean audit(LabWorkerCertificateAuditReq req, Long userId) {
        return labAcceptanceCertificateService.audit(req,userId);
    }

    public void delete(Long id) {
        LambdaQueryWrapper<LabAcceptanceCertificate> wrapper = Wrappers.lambdaQuery(LabAcceptanceCertificate.class);
        LabAcceptanceCertificateManage context = (LabAcceptanceCertificateManage) AopContext.currentProxy();
        context.buildQuery(wrapper, id);
        LabAcceptanceCertificate record = labAcceptanceCertificateService.getOne(wrapper);
        if (Objects.isNull(record)){
            throw new BizException("无法删除!");
        }
        labAcceptanceCertificateService.removeById(id);
    }

    @LambdaDataScope(type = LambdaDataScopeTypeEnum.ALL)
    public void buildQuery(LambdaQueryWrapper<LabAcceptanceCertificate> wrapper, Long id) {
        wrapper.eq(LabAcceptanceCertificate::getId,id);
    }
}
