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.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.constant.GenderEnum;
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.LabWorkerCertificate;
import com.ningdatech.carapi.industry.entity.LabWorkerCertificateChange;
import com.ningdatech.carapi.industry.enums.AddTypeEnum;
import com.ningdatech.carapi.industry.enums.LabWorkerCertificateTypeEnum;
import com.ningdatech.carapi.industry.model.dto.LabWorkerCertificateExportDto;
import com.ningdatech.carapi.industry.model.dto.LabWorkerCertificateImportDto;
import com.ningdatech.carapi.industry.model.req.LabWorkerCertificateAuditReq;
import com.ningdatech.carapi.industry.model.req.LabWorkerCertificateListReq;
import com.ningdatech.carapi.industry.model.req.LabWorkerCertificateReq;
import com.ningdatech.carapi.industry.model.vo.LabWorkerCertificateChangeListVo;
import com.ningdatech.carapi.industry.model.vo.LabWorkerCertificateListVo;
import com.ningdatech.carapi.industry.service.ILabWorkerCertificateChangeService;
import com.ningdatech.carapi.industry.service.ILabWorkerCertificateService;
import com.ningdatech.carapi.sys.entity.Company;
import com.ningdatech.carapi.sys.event.ImportDataEvent;
import com.ningdatech.carapi.sys.helper.CompaniesCacheHelper;
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.lang.Assert;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * LabWorkerCertificateManage
 * </p>
 *
 * @author WendyYang
 * @since 14:57 2022/11/4
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class LabWorkerCertificateManage {

    private final CompaniesCacheHelper companiesCacheHelper;
    private final CompanyService companyService;
    private final RegionsCacheHelper regionsCacheHelper;
    private final ILabWorkerCertificateService labWorkerCertificateService;

    private final ILabWorkerCertificateChangeService labWorkerCertificateChangeService;

    public PageVo<LabWorkerCertificateListVo> labWorkerCertificateList(LabWorkerCertificateListReq req) {
        LambdaQueryWrapper<LabWorkerCertificate> query = Wrappers.lambdaQuery(LabWorkerCertificate.class);
        LabWorkerCertificateManage context = (LabWorkerCertificateManage) AopContext.currentProxy();
        context.buildLabWorkerCertificateQuery(query, req);
        Page<LabWorkerCertificate> page = labWorkerCertificateService.page(req.page(), query);
        if (0L == page.getTotal()) {
            return PageVo.empty();
        }
        List<LabWorkerCertificateListVo> data = CollUtils.convert(page.getRecords(), w -> {
            LabWorkerCertificateListVo vo = BeanUtil.copyProperties(w, LabWorkerCertificateListVo.class);
            vo.setRegionName(regionsCacheHelper.getDisplayName(w.getRegionId()));
            vo.setGenderName(GenderEnum.getDescByCode(w.getGender()));
            vo.setUserName(w.getUserName());
            return vo;
        });
        return PageVo.of(data, page.getTotal());
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildLabWorkerCertificateQuery(LambdaQueryWrapper<LabWorkerCertificate> query, LabWorkerCertificateListReq req) {
        query.like(StrUtil.isNotBlank(req.getCompanyName()), LabWorkerCertificate::getCompanyName, req.getCompanyName())
                .ge(Objects.nonNull(req.getStartDate()), LabWorkerCertificate::getConferDate, req.getStartDate())
                .le(Objects.nonNull(req.getEndDate()), LabWorkerCertificate::getConferDate, req.getEndDate())
                .eq(Objects.nonNull(req.getCertificateType()), LabWorkerCertificate::getCertificateType, req.getCertificateType())
                .orderByDesc(LabWorkerCertificate::getUpdateOn);
    }

    public void labWorkerCertificateExport(HttpServletResponse response, LabWorkerCertificateListReq req) {
        req.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        PageVo<LabWorkerCertificateListVo> page = this.labWorkerCertificateList(req);
        List<LabWorkerCertificateExportDto> collect = page.getRecords().stream().map(w -> {
            LabWorkerCertificateExportDto dto = BeanUtil.copyProperties(w, LabWorkerCertificateExportDto.class);
            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);
            dto.setGender(GenderEnum.getDescByCode(w.getGender()));
            return dto;
        }).collect(Collectors.toList());
        String fileName;
        if (req.getCertificateType() == LabWorkerCertificateTypeEnum.QUALIFICATION.getCode()) {
            fileName = "试验室人员从业资格证-证书信息";
        } else {
            fileName = "实验室人员继续教育合格证-证书信息";
        }
        ExcelDownUtil.setFileName(fileName, response);
        // 数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), LabWorkerCertificateExportDto.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

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

                    @Override
                    public void invoke(LabWorkerCertificateImportDto 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<LabWorkerCertificateImportDto> records) {
        Long userId = LoginUserUtil.getUserId();
        LocalDateTime now = LocalDateTime.now();
        List<String> companyNames = CollUtils.fieldList(records, LabWorkerCertificateImportDto::getCompanyName);
        List<Company> companies = companyService.listCompanyByCompanyNames(companyNames);
        Map<String, Company> companyMap = CollUtils.listToMap(companies, Company::getName);
        List<LabWorkerCertificate> list = new ArrayList<>();
        records.forEach(w -> {
            Company company = companyMap.get(w.getCompanyName());
            if (company == null) {
                return;
            }
            LabWorkerCertificate certificate = new LabWorkerCertificate();
            certificate.setCertificateNo(w.getCertificateNo());
            certificate.setIdCard(w.getIdCard());
            certificate.setRemark(w.getRemark());
            certificate.setGender(GenderEnum.getByValue(w.getGender()).getCode());
            certificate.setRegionId(company.getRegionId());
            certificate.setUserName(w.getUsername());
            certificate.setValidDate(NdDateUtils.date2LocalDate(w.getEndDate()));
            certificate.setConferDate(NdDateUtils.date2LocalDate(w.getStartDate()));
            certificate.setCompanyName(company.getName());
            certificate.setCompanyId(company.getId());
            certificate.setCreateBy(userId);
            certificate.setCreateOn(now);
            certificate.setUpdateBy(userId);
            certificate.setUpdateOn(now);
            list.add(certificate);
            labWorkerCertificateService.saveBatch(list);
        });
    }

    public void saveOrUpdate(LabWorkerCertificateReq req) {
        Integer addType = req.getAddType();
        //说明是新增证书
        LabWorkerCertificate labWorkerCertificate = new LabWorkerCertificate();
        if (AddTypeEnum.NEW.getCode().equals(addType)) {
            if (Objects.nonNull(req.getId())){
                // 说明为编辑
                labWorkerCertificate.setId(req.getId());
            }
            labWorkerCertificate.setRegionId(req.getRegionId());
            labWorkerCertificate.setCompanyId(req.getCompanyId());
            labWorkerCertificate.setCompanyName(req.getCompanyName());
            labWorkerCertificate.setCreateOn(LocalDateTime.now());
            labWorkerCertificate.setCreateBy(LoginUserUtil.getUserId());
            labWorkerCertificate.setUpdateOn(LocalDateTime.now());
            labWorkerCertificate.setUpdateOn(LocalDateTime.now());
            labWorkerCertificate.setGender(req.getGender());
            labWorkerCertificate.setIdCard(req.getIdCard());
            labWorkerCertificate.setCertificateNo(req.getCertificateNo());
            labWorkerCertificate.setConferDate(req.getConferDate());
            labWorkerCertificate.setValidDate(req.getValidDate());
            labWorkerCertificate.setRemark(req.getRemark());
            labWorkerCertificate.setCertificateType(req.getCertificateType());
            labWorkerCertificate.setConferOrg(req.getConferOrg());
            labWorkerCertificateService.saveOrUpdate(labWorkerCertificate);
        } else if (AddTypeEnum.REPLACE.getCode().equals(req.getAddType())) {
            // 说明是换证
            //创建新的证书实体，并装配证书信息,保存到换证列表中
            String applicationItem = req.getApplicationItem();
            String applicationReason = req.getApplicationReason();
            if (Objects.isNull(applicationItem) || Objects.isNull(applicationReason)){
                throw new BizException("申请事项和申请原因不能为空!");
            }
            LabWorkerCertificateChange labWorkerCertificateChange = new LabWorkerCertificateChange();
            if (Objects.nonNull(req.getId())){
                // 说明为编辑
                labWorkerCertificateChange.setId(req.getId());
            }
            labWorkerCertificateChange.setCompanyName(req.getCompanyName());
            labWorkerCertificateChange.setCompanyId(req.getCompanyId());
            labWorkerCertificateChange.setRegionId(req.getRegionId());
            labWorkerCertificateChange.setUserName(req.getUserName());
            labWorkerCertificateChange.setGender(req.getGender());
            labWorkerCertificateChange.setIdCard(req.getIdCard());
            labWorkerCertificateChange.setCertificateNo(req.getCertificateNo());
            labWorkerCertificateChange.setReplacementTime(req.getReplaceDate());
            labWorkerCertificateChange.setValidDate(req.getValidDate());
            labWorkerCertificateChange.setRemark(req.getRemark());
            labWorkerCertificateChange.setCertificateType(req.getCertificateType());
            labWorkerCertificateChange.setApplicationItem(req.getApplicationItem());
            labWorkerCertificateChange.setApplicationReason(req.getApplicationReason());
            labWorkerCertificateChange.setConferOrg(req.getConferOrg());

            labWorkerCertificateChange.setCreateOn(LocalDateTime.now());
            labWorkerCertificateChange.setCreateBy(LoginUserUtil.getUserId());
            labWorkerCertificateChange.setUpdateOn(LocalDateTime.now());
            labWorkerCertificateChange.setUpdateOn(LocalDateTime.now());

            labWorkerCertificateChangeService.saveOrUpdate(labWorkerCertificateChange);
        }
    }

    public PageVo<LabWorkerCertificateChangeListVo> changeCertificate(LabWorkerCertificateListReq req) {
        LambdaQueryWrapper<LabWorkerCertificateChange> wrapper = Wrappers.lambdaQuery(LabWorkerCertificateChange.class);
        LabWorkerCertificateManage context = (LabWorkerCertificateManage) AopContext.currentProxy();
        context.buildLabWorkerCertificateChangeQuery(wrapper, req);
        Page<LabWorkerCertificateChange> page = labWorkerCertificateChangeService.page(req.page(), wrapper);
        if (page.getTotal() == 0) {
            return PageVo.empty();
        }
        List<LabWorkerCertificateChangeListVo> records = CollUtils.convert(page.getRecords(), w -> {
            LabWorkerCertificateChangeListVo resVo = BeanUtil.copyProperties(w, LabWorkerCertificateChangeListVo.class);
            resVo.setReplaceDate(w.getReplacementTime());
            resVo.setRegionName(regionsCacheHelper.getDisplayName(w.getRegionId()));
            resVo.setGenderName(GenderEnum.getDescByCode(w.getGender()));
            return resVo;
        });
        return PageVo.of(records, page.getTotal());
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildLabWorkerCertificateChangeQuery(LambdaQueryWrapper<LabWorkerCertificateChange> wrapper, LabWorkerCertificateListReq req) {
        wrapper.like(StrUtil.isNotBlank(req.getCompanyName()), LabWorkerCertificateChange::getCompanyName, req.getCompanyName())
                .ge(Objects.nonNull(req.getStartDate()), LabWorkerCertificateChange::getReplacementTime, req.getStartDate())
                .le(Objects.nonNull(req.getEndDate()), LabWorkerCertificateChange::getReplacementTime, req.getEndDate())
                .eq(Objects.nonNull(req.getCertificateType()), LabWorkerCertificateChange::getCertificateType, req.getCertificateType())
                .orderByDesc(LabWorkerCertificateChange::getUpdateOn);
    }

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

    public Boolean cancelAudit(LabWorkerCertificateAuditReq req, Long userId) {
        return labWorkerCertificateService.cancelAudit(req, userId);
    }

    public void delete(Long id) {

        LambdaQueryWrapper<LabWorkerCertificate> wrapper = Wrappers.lambdaQuery(LabWorkerCertificate.class);
        LabWorkerCertificateManage context = (LabWorkerCertificateManage) AopContext.currentProxy();
        context.buildQuery(wrapper, id);
        LabWorkerCertificate record = labWorkerCertificateService.getOne(wrapper);
        if (Objects.isNull(record)){
            throw new BizException("无法删除!");
        }
        labWorkerCertificateService.removeById(id);
    }
    @LambdaDataScope(type = LambdaDataScopeTypeEnum.ALL)
    public void buildQuery(LambdaQueryWrapper<LabWorkerCertificate> wrapper, Long id) {
        wrapper.eq(LabWorkerCertificate::getId,id);
    }
}