package com.qmth.distributed.print.business.templete.execute;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.qmth.distributed.print.business.bean.dto.BasicExamStudentDto;
import com.qmth.distributed.print.business.service.BasicExamService;
import com.qmth.distributed.print.business.service.BasicExamStudentService;
import com.qmth.distributed.print.business.templete.importData.SyncImportTaskTemplate;
import com.qmth.distributed.print.business.templete.service.TaskLogicService;
import com.qmth.teachcloud.common.annotation.ExcelNote;
import com.qmth.teachcloud.common.bean.vo.FilePathVo;
import com.qmth.teachcloud.common.contant.SpringContextHolder;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicExam;
import com.qmth.teachcloud.common.entity.BasicExamStudent;
import com.qmth.teachcloud.common.entity.TBTask;
import com.qmth.teachcloud.common.enums.*;
import com.qmth.teachcloud.common.service.FileUploadService;
import com.qmth.teachcloud.common.service.TBTaskService;
import com.qmth.teachcloud.common.util.Result;
import com.qmth.teachcloud.common.util.ResultUtil;
import com.qmth.teachcloud.mark.service.MarkPaperService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.*;

/**
 * @Description: 考生字典导入同步任务
 * @Author: CaoZixuan
 * @Date: 2024-02-26
 */
@Service
public class SyncBasicExamStudentImportService extends SyncImportTaskTemplate {

    private final static Logger log = LoggerFactory.getLogger(SyncBasicExamStudentImportService.class);

    public static final String OBJ_TITLE = "考生字典数据";

    @Resource
    private BasicExamService basicExamService;
    @Resource
    private BasicExamStudentService basicExamStudentService;
    @Resource
    private MarkPaperService markPaperService;
    @Resource
    private FileUploadService fileUploadService;

    @Override
    public Result importTask(Map<String, Object> map) throws Exception {
        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
        InputStream inputStream = super.getUploadFileInputStream(tbTask);
        map.put("inputStream", inputStream);

        StringJoiner stringJoinerSummary = new StringJoiner("\n").add(
                MessageFormat.format("{0}{1}{2}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN),
                        BEGIN_TITLE, OBJ_TITLE));
        tbTask.setStatus(TaskStatusEnum.RUNNING);
        TBTaskService tbTaskService = SpringContextHolder.getBean(TBTaskService.class);
        tbTaskService.updateById(tbTask);
        int dataCount = 0;
        int successCount = 0;
        int errorCount = 0;
        List<BasicExamStudentDto> errorDataList = new ArrayList<>();

        try {
            TaskLogicService taskLogicService = SpringContextHolder.getBean(TaskLogicService.class);

            // 执行导入考务数据
            Map<String, Object> result = taskLogicService.executeImportBasicExamStudentLogic(map);
            dataCount = Integer.parseInt(String.valueOf(result.get(SystemConstant.DATA_COUNT)));
            successCount = Integer.parseInt(String.valueOf(result.get(SystemConstant.SUCCESS_DATA_COUNT)));
            errorCount = Integer.parseInt(String.valueOf(result.get(SystemConstant.ERROR_DATA_COUNT)));

            // 无异常数据
            if (result.containsKey(SystemConstant.DATASOURCE)) {
                List<BasicExamStudent> basicExamStudentList = JSON.parseArray(JSON.toJSONString(result.get(SystemConstant.DATASOURCE)), BasicExamStudent.class);
                basicExamStudentService.saveOrUpdateBatch(basicExamStudentList);
                // 模式4，直接进扫描阅卷库
                BasicExam basicExam = basicExamService.getById(tbTask.getExamId());
                if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
                    taskLogicService.saveMarkStudent(tbTask.getExamId(), basicExamStudentList);

                    // 重新统计试卷下考生数量
                    basicExamStudentList.stream().map(BasicExamStudent::getPaperNumber).distinct().forEach(m-> markPaperService.updateStudentCountByExamIdAndPaperNumberAndPaperType(tbTask.getExamId(), m, SystemConstant.DEFAULT_PAPER_TYPE_A));

                    // 更改过试卷编号后，该试卷编号下没有考生则删除该试卷
                    List<String> oldPaperNumberList = JSON.parseArray(JSON.toJSONString(result.get("oldPaperNumberList")), String.class);
                    for (String paperNumber : oldPaperNumberList) {
                        markPaperService.deleteByExamIdAndPaperNumber(tbTask.getExamId(), paperNumber, true);
                    }
                }
            } else if (result.containsKey(SystemConstant.ERROR_DATA_LIST)) {
                // 有异常数据
                errorDataList = JSON.parseArray(JSON.toJSONString(result.get(SystemConstant.ERROR_DATA_LIST)),
                        BasicExamStudentDto.class);
                throw ExceptionResultEnum.ERROR.exception("导入考生字典失败,请通过'导入结果查询'查看错误原因");
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e.getMessage());
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        } finally {//生成文件
            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}{4}{5}{6}{7}",
                    DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, dataCount,
                    FINISH_TOTAL_SIZE, successCount, FINISH_SUCCESS_SIZE, errorCount, FINISH_ERROR_SIZE));
            if (CollectionUtils.isNotEmpty(errorDataList)) {
                tbTask.setResult(TaskResultEnum.ERROR);
                String createExcelError = "";
                try {
                    File excelFileTemp = SystemConstant.getFileTempVar(SystemConstant.EXCEL_PREFIX);
                    this.createLocalErrorExcel(errorDataList, excelFileTemp);
                    String fileName = SystemConstant.getNanoId() + SystemConstant.EXCEL_PREFIX;
                    FilePathVo filePathVo = fileUploadService.uploadFile(excelFileTemp, UploadFileEnum.FILE, fileName);
                    tbTask.setErrorFilePath(JSON.toJSONString(filePathVo));
                } catch (Exception e) {
                    createExcelError = e.getMessage();
                    log.error("创建考生字典导入错误数据文件失败: " + e.getMessage());
                } finally {
                    tbTask.setSummary("创建考生字典导入错误数据文件失败" + stringJoinerSummary + createExcelError);
                }
            } else {
                tbTask.setSummary(stringJoinerSummary.toString());
                tbTask.setResult(TaskResultEnum.SUCCESS);
            }
            tbTask.setStatus(TaskStatusEnum.FINISH);
            tbTaskService.updateById(tbTask);
        }
        return ResultUtil.ok();
    }

    private void createLocalErrorExcel(List<BasicExamStudentDto> basicExamStudentDtoList, File excelFileTemp)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {

        List<Field> fields = Arrays.asList(BasicExamStudentDto.class.getDeclaredFields());

        log.debug("导出Excel开始...");
        XSSFWorkbook wb = new XSSFWorkbook();
        XSSFSheet sheet = wb.createSheet("考生字典导入");

        Font defaultFont = wb.createFont();
        defaultFont.setFontHeightInPoints((short) 12);
        defaultFont.setFontName("宋体");

        int cellCount = fields.size();
        // 说明
        XSSFCellStyle describeStyle = wb.createCellStyle();
        XSSFDataFormat format = wb.createDataFormat();
        describeStyle.setAlignment(HorizontalAlignment.LEFT);
        Font describeFont = wb.createFont();
        describeFont.setFontHeightInPoints((short) 12);
        describeFont.setFontName("宋体");
        describeFont.setColor(IndexedColors.RED.getIndex());
        describeStyle.setFont(describeFont);
        describeStyle.setDataFormat(format.getFormat("@"));
        String describe = SystemConstant.BASIC_EXAM_STUDENT_DESCRIBE;
        describe = describe.trim();
        XSSFRow rowDescribe = sheet.createRow(0);
        rowDescribe.setHeightInPoints(100); //行高设置成100px
        for (int i = 0; i < cellCount; i++) {
            XSSFCell cell = rowDescribe.createCell(i);
            if (i == 0) {
                cell.setCellValue(describe);
                cell.setCellStyle(describeStyle);
            }
        }
        CellRangeAddress region = new CellRangeAddress(0, 0, 0, cellCount - 1);
        sheet.addMergedRegion(region);

        // 表头行
        XSSFCellStyle headerStyle = wb.createCellStyle();
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headerStyle.setAlignment(HorizontalAlignment.CENTER);
        headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headerStyle.setFont(defaultFont);
        XSSFRow rowHead = sheet.createRow(1);
        for (int i = 0; i < fields.size(); i++) {
            XSSFCell cell = rowHead.createCell(i);
            Field field = fields.get(i);
            String title = "";
            ExcelNote excelNote = field.getAnnotation(ExcelNote.class);

            if (Objects.isNull(excelNote)) {
                if (i == fields.size() - 1) {
                    title = "异常信息";
                } else {
                    throw ExceptionResultEnum.ERROR.exception("未能获取dto属性注解");
                }
            } else {
                title = excelNote.value();
            }
            cell.setCellValue(title);
            cell.setCellStyle(headerStyle);
        }
        XSSFCell lastCell = rowHead.createCell(cellCount - 1);
        lastCell.setCellValue("异常信息");
        lastCell.setCellStyle(headerStyle);

        // 内容行
        XSSFCellStyle exampleStyle = wb.createCellStyle();
        exampleStyle.setAlignment(HorizontalAlignment.LEFT);
        exampleStyle.setFont(defaultFont);

        for (int i = 0; i < basicExamStudentDtoList.size(); i++) {
            BasicExamStudentDto basicExamStudentDto = basicExamStudentDtoList.get(i);
            XSSFRow row = sheet.createRow(i + 2);
            for (int j = 0; j < fields.size(); j++) {
                XSSFCell cell = row.createCell(j);
                Field head = fields.get(j);
                String methodName = "get" + SystemConstant.initCap(head.getName());
                Method getMethod = basicExamStudentDto.getClass().getDeclaredMethod(methodName);
                String value = String.valueOf(getMethod.invoke(basicExamStudentDto));
                if (SystemConstant.strNotNull(value)) {
                    cell.setCellValue(value);
                } else {
                    cell.setCellValue("");
                }
                cell.setCellStyle(exampleStyle);
            }
        }
        for (int i = 0; i < cellCount; i++) {
            sheet.autoSizeColumn(i);
            int width = sheet.getColumnWidth(i)  * 17 / 10;
            sheet.setColumnWidth(i, Math.min(width, 255 * 256));
        }

        FileOutputStream outputStream = new FileOutputStream(excelFileTemp);
        wb.write(outputStream);
        outputStream.flush();
        outputStream.close();
    }
}
