package com.ningdatech.carapi.industry.manage;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.carapi.industry.contants.CertificateContant;
import com.ningdatech.carapi.industry.entity.OperatorIndexScoreInfo;
import com.ningdatech.carapi.industry.entity.OperatorScoreInfo;
import com.ningdatech.carapi.industry.enums.OperatorAssessmentIndexEnum;
import com.ningdatech.carapi.industry.enums.QuarterEnum;
import com.ningdatech.carapi.industry.model.dto.OperatorAssessmentDTO;
import com.ningdatech.carapi.industry.model.dto.OperatorsAssessmentDetailsExportDTO;
import com.ningdatech.carapi.industry.model.vo.OperatorScoreDetailVO;
import com.ningdatech.carapi.industry.service.IOperatorIndexScoreInfoService;
import com.ningdatech.carapi.scheduler.contants.TaskConstant;
import com.ningdatech.carapi.sys.entity.Operator;
import com.ningdatech.carapi.sys.service.IOperatorScoreInfoService;
import com.ningdatech.carapi.sys.service.OperatorService;

import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author CMM
 * @since 2023/01/05 09:18
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class OperatorAssessmentManage {

    private final IOperatorScoreInfoService operatorScoreInfoService;

    private final IOperatorIndexScoreInfoService operatorIndexScoreInfoService;

    private final OperatorService operatorService;

    public OperatorScoreDetailVO getOperatorScore(OperatorAssessmentDTO data) {
        OperatorScoreDetailVO operatorScoreDetailVO = new OperatorScoreDetailVO();
        Integer quarter = data.getQuarter();
        Long operatorId = data.getId();
        String year = data.getYear();
        LambdaUpdateWrapper<OperatorScoreInfo> wrapper = Wrappers.lambdaUpdate(OperatorScoreInfo.class);
        wrapper.eq(OperatorScoreInfo::getQuarter, quarter)
                .eq(OperatorScoreInfo::getOperatorId, operatorId)
                .eq(OperatorScoreInfo::getYear,year);
        List<OperatorIndexScoreInfo> operatorIndexScoreInfos = operatorIndexScoreInfoService.list();
        OperatorScoreInfo operatorScoreInfo = operatorScoreInfoService.getOne(wrapper);
        assemblyOperatorIndexScore(operatorScoreDetailVO, operatorIndexScoreInfos);
        if (Objects.isNull(operatorScoreInfo)){
            // 查询条件下没有该运营商的考核分数信息，各项分数默认显示满分
            log.info("未查询到运营商考核分数信息!");
            assemblyOperatorInitialScore(operatorScoreDetailVO,operatorIndexScoreInfos);
            operatorScoreDetailVO.setTotalScore(TaskConstant.Data.OPERATOR_ASSESSMENT_SCORE_HUNDRED);
            return operatorScoreDetailVO;
        }
        assemblyOperatorScore(operatorScoreDetailVO, operatorScoreInfo);
        return operatorScoreDetailVO;
    }

    private void assemblyOperatorInitialScore(OperatorScoreDetailVO operatorScoreDetailVO,List<OperatorIndexScoreInfo> operatorIndexScoreInfos) {
        for (OperatorIndexScoreInfo operatorIndexScoreInfo : operatorIndexScoreInfos) {
            switch (OperatorAssessmentIndexEnum.getEnumByValue(operatorIndexScoreInfo.getOperatorScoreIndex())) {
                case UPLOAD_QUALIFICATION:
                    operatorScoreDetailVO.setUploadQualification(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                case UPLOAD_FREQUENCY_QUANTITY:
                    operatorScoreDetailVO.setUploadFrequencyQuantity(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                case FIELD_INTEGRITY:
                    operatorScoreDetailVO.setFieldIntegrity(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                case TIME_SENSITIVE:
                    operatorScoreDetailVO.setTimeSensitive(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                case POSITION_DIRECTION_CORRECTNESS_CONSISTENCY:
                    operatorScoreDetailVO.setPositionDirectionCorrectnessConsistency(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                case SPEED_CORRECTNESS_CONSISTENCY:
                    operatorScoreDetailVO.setSpeedCorrectnessConsistency(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                case TIME_CONSISTENCY:
                    operatorScoreDetailVO.setTimeConsistency(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                case POSITION_CONSISTENCY:
                    operatorScoreDetailVO.setPositionConsistency(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    break;
                default:
                    throw new BizException("Unexpected value: " + operatorIndexScoreInfo.getOperatorScoreIndex());
            }
        }
    }

    private void assemblyOperatorIndexScore(OperatorScoreDetailVO operatorScoreDetailVO, List<OperatorIndexScoreInfo> operatorIndexScoreInfos) {
        for (OperatorIndexScoreInfo operatorIndexScoreInfo : operatorIndexScoreInfos) {
            switch (OperatorAssessmentIndexEnum.getEnumByValue(operatorIndexScoreInfo.getOperatorScoreIndex())){
                case UPLOAD_QUALIFICATION:
                    operatorScoreDetailVO.setUploadQualificationIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setUploadQualificationName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                case UPLOAD_FREQUENCY_QUANTITY:
                    operatorScoreDetailVO.setUploadFrequencyQuantityIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setUploadFrequencyQuantityName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                case FIELD_INTEGRITY:
                    operatorScoreDetailVO.setFieldIntegrityIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setFieldIntegrityName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                case TIME_SENSITIVE:
                    operatorScoreDetailVO.setTimeSensitiveIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setTimeSensitiveName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                case POSITION_DIRECTION_CORRECTNESS_CONSISTENCY:
                    operatorScoreDetailVO.setPositionDirectionCorrectnessConsistencyIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setPositionDirectionCorrectnessConsistencyName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                case SPEED_CORRECTNESS_CONSISTENCY:
                    operatorScoreDetailVO.setSpeedCorrectnessConsistencyIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setSpeedCorrectnessConsistencyName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                case TIME_CONSISTENCY:
                    operatorScoreDetailVO.setTimeConsistencyIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setTimeConsistencyName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                case POSITION_CONSISTENCY:
                    operatorScoreDetailVO.setPositionConsistencyIndex(operatorIndexScoreInfo.getOperatorScoreIndexScore());
                    operatorScoreDetailVO.setPositionConsistencyName(operatorIndexScoreInfo.getOperatorScoreIndexName());
                    break;
                default:
                    throw new BizException("Unexpected value: " + operatorIndexScoreInfo.getOperatorScoreIndex());
            }
        }
    }

    private void assemblyOperatorScore(OperatorScoreDetailVO operatorScoreDetailVO, OperatorScoreInfo operatorScoreInfo) {
        Integer score = operatorScoreInfo.getUploadQualification();
        operatorScoreDetailVO.setUploadQualification(score);
        Integer score2 = operatorScoreInfo.getUploadFrequencyQuantity();
        operatorScoreDetailVO.setUploadFrequencyQuantity(score2);
        Integer score3 = operatorScoreInfo.getFieldIntegrity();
        operatorScoreDetailVO.setFieldIntegrity(score3);
        Integer score4 = operatorScoreInfo.getTimeSensitive();
        operatorScoreDetailVO.setTimeSensitive(score4);
        Integer score5 = operatorScoreInfo.getPositionDirectionCorrectnessConsistency();
        operatorScoreDetailVO.setPositionDirectionCorrectnessConsistency(score5);
        Integer score6 = operatorScoreInfo.getSpeedCorrectnessConsistency();
        operatorScoreDetailVO.setSpeedCorrectnessConsistency(score6);
        Integer score7 = operatorScoreInfo.getTimeConsistency();
        operatorScoreDetailVO.setTimeConsistency(score7);
        Integer score8 = operatorScoreInfo.getPositionConsistency();
        operatorScoreDetailVO.setPositionConsistency(score8);
        int totalScore = score + score2 + score3 + score4 + score5 + score6 + score7 + score8;
        operatorScoreDetailVO.setTotalScore(totalScore);
    }

    public void exportDocx(HttpServletResponse response, OperatorAssessmentDTO data) {
        OperatorScoreDetailVO operatorScore = getOperatorScore(data);
        Operator operator = operatorService.getById(data.getId());
        InputStream in = null;
        String fileName = "运营商考核详情";
        try {
            //获取本地目录的word模板
            in =  this.getClass().getClassLoader().getResourceAsStream("template/" + fileName + ".docx");
            //注册xdocreport实例并加载FreeMarker模板引擎
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
            //创建xdocreport上下文对象
            IContext context = report.createContext();

            List<OperatorsAssessmentDetailsExportDTO> oadList = new ArrayList<>();
            oadList.add(new OperatorsAssessmentDetailsExportDTO("1",OperatorAssessmentIndexEnum.UPLOAD_QUALIFICATION.getDesc(),CertificateContant.ScoringRubric.UPLOAD_QUALIFICATION_SCORING_RUBRIC,String.valueOf(operatorScore.getUploadQualificationIndex()),String.valueOf(operatorScore.getUploadQualification())));
            oadList.add(new OperatorsAssessmentDetailsExportDTO("2",OperatorAssessmentIndexEnum.UPLOAD_FREQUENCY_QUANTITY.getDesc(),CertificateContant.ScoringRubric.UPLOAD_FREQUENCY_QUANTITY_SCORING_RUBRIC,String.valueOf(operatorScore.getUploadFrequencyQuantityIndex()),String.valueOf(operatorScore.getUploadFrequencyQuantity())));
            oadList.add(new OperatorsAssessmentDetailsExportDTO("3",OperatorAssessmentIndexEnum.FIELD_INTEGRITY.getDesc(),CertificateContant.ScoringRubric.FIELD_INTEGRITY_SCORING_RUBRIC,String.valueOf(operatorScore.getFieldIntegrityIndex()),String.valueOf(operatorScore.getFieldIntegrity())));
            oadList.add(new OperatorsAssessmentDetailsExportDTO("4",OperatorAssessmentIndexEnum.TIME_SENSITIVE.getDesc(),CertificateContant.ScoringRubric.TIME_SENSITIVE_SCORING_RUBRIC,String.valueOf(operatorScore.getTimeSensitiveIndex()),String.valueOf(operatorScore.getTimeSensitive())));
            oadList.add(new OperatorsAssessmentDetailsExportDTO("5",OperatorAssessmentIndexEnum.POSITION_DIRECTION_CORRECTNESS_CONSISTENCY.getDesc(),CertificateContant.ScoringRubric.POSITION_DIRECTION_CORRECTNESS_CONSISTENCY_SCORING_RUBRIC,String.valueOf(operatorScore.getPositionDirectionCorrectnessConsistencyIndex()),String.valueOf(operatorScore.getPositionDirectionCorrectnessConsistency())));
            oadList.add(new OperatorsAssessmentDetailsExportDTO("6",OperatorAssessmentIndexEnum.SPEED_CORRECTNESS_CONSISTENCY.getDesc(),CertificateContant.ScoringRubric.SPEED_CORRECTNESS_CONSISTENCY_SCORING_RUBRIC,String.valueOf(operatorScore.getSpeedCorrectnessConsistencyIndex()),String.valueOf(operatorScore.getSpeedCorrectnessConsistency())));
            oadList.add(new OperatorsAssessmentDetailsExportDTO("7",OperatorAssessmentIndexEnum.TIME_CONSISTENCY.getDesc(),CertificateContant.ScoringRubric.TIME_CONSISTENCY_SCORING_RUBRIC,String.valueOf(operatorScore.getTimeConsistencyIndex()),String.valueOf(operatorScore.getTimeConsistency())));
            oadList.add(new OperatorsAssessmentDetailsExportDTO("8",OperatorAssessmentIndexEnum.POSITION_CONSISTENCY.getDesc(),CertificateContant.ScoringRubric.POSITION_CONSISTENCY_SCORING_RUBRIC,String.valueOf(operatorScore.getPositionConsistencyIndex()),String.valueOf(operatorScore.getPositionConsistency())));
            //将需要替换的数据数据添加到上下文中
            //其中key为word模板中的域名，value是需要替换的值
            context.put("operatorName",operator.getName());
            context.put("date", data.getYear() + "-" + QuarterEnum.getDescByCode(data.getQuarter()));
            context.put("oadList",oadList);
            context.put("totalScore",operatorScore.getTotalScore());

            //创建字段元数据，需要表格才加下面这两行，否则不用
            FieldsMetadata fm = report.createFieldsMetadata();
            //Word模板中的表格数据对应的集合类型
            fm.load("oadList", OperatorsAssessmentDetailsExportDTO.class, true);

            // 将结果写入流中，供前端下载
            try {
                response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeName(fileName) + ".docx");
                OutputStream out = response.getOutputStream();
                //处理word文档并输出
                report.process(context, out);
                response.flushBuffer();
            } catch (IOException e) {
                log.error("流错误!");
            }
        } catch (IOException e) {
            log.error("读取Word模板异常",e);
        } catch (XDocReportException e) {
            log.error("word模板生成失败",e);
        } finally {
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static String encodeName(String name) {
        String fileName;
        try {
            fileName = URLEncoder.encode(name, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("文件名编码异常：", e);
            fileName = UUID.randomUUID().toString().replace("-", "");
        }
        return fileName;
    }
}
