package com.koobietech.eas.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.github.pagehelper.PageHelper;
import com.koobietech.eas.common.constant.FileType;
import com.koobietech.eas.common.constant.Gender;
import com.koobietech.eas.common.exception.EasException;
import com.koobietech.eas.common.utils.ArchiveManager;
import com.koobietech.eas.common.utils.DateManager;
import com.koobietech.eas.common.utils.SecurityManager;
import com.koobietech.eas.dao.dto.ArchivesDto;
import com.koobietech.eas.dao.dto.EasArcTlsStudentsDto;
import com.koobietech.eas.mbg.mapper.EasArcArchivesMapper;
import com.koobietech.eas.mbg.mapper.EasArcTlsStudentsMapper;
import com.koobietech.eas.mbg.mapper.EasSysStudentMapper;
import com.koobietech.eas.mbg.model.EasArcArchives;
import com.koobietech.eas.mbg.model.EasArcTlsStudents;
import com.koobietech.eas.mbg.model.EasArcTlsStudentsExample;
import com.koobietech.eas.mbg.model.EasSysStudent;
import com.koobietech.eas.service.EasArchivesFilesService;
import com.koobietech.eas.service.EasStuProfileService;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Service
public class EasStuProfileServiceImpl implements EasStuProfileService {

    private static final String TEMPLATE_PATH = "temp/StuRegistTemp.docx";
    private static final String PHOTO_PATH = "temp/kun.jpeg";
    @Resource
    private EasArcTlsStudentsMapper easArcTlsStudentsMapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private EasSysStudentMapper easSysStudentMapper;
    @Resource
    private EasArcArchivesMapper easArcArchivesMapper;
    @Resource
    private EasArchivesFilesService easArchivesFilesService;

    @Override
    public boolean add(EasArcTlsStudents easArcTlsStudents) {

        //使用try-with-resources 语句 保证流的关闭
        try (InputStream wordStream = getClass().getClassLoader().getResourceAsStream(TEMPLATE_PATH)) {
            assert wordStream != null;
            try (XWPFDocument doc = new XWPFDocument(wordStream)) {
                //调用内部类方法 生成学号
                String studentNumber = generateStudentNumber(easArcTlsStudents);

                easArcTlsStudents.setStudentNumber(studentNumber);
                Map<String, Object> map = generateDataMap(easArcTlsStudents, studentNumber);
                replacePlaceholders(doc, map);
                //这里会生成一个学生档案保存本地 目前这里有bug保存不成功 而且文件后缀有错误
                ArchivesDto archivesDto = insertEasArcArchives(easArcTlsStudents, doc);
                if ( !archivesDto.isStatus() ) {
                    throw new EasException("EasArcArchives保存失败", 8002);
                }

                //将easArcTlsStudents 保存到数据库
                easArcTlsStudents.setArchiveNumber(archivesDto.getArchiveCode());
                boolean isTlsStudentsInsert = insertEasArcTlsStudents(easArcTlsStudents);
                if (!isTlsStudentsInsert) {
                    throw new EasException("EasArcTlsStudents保存失败", 8000);
                }
                boolean isSysStudentsInsert = insertEasSysStudents(easArcTlsStudents);
                if (!isSysStudentsInsert) {
                    throw new EasException("EasSysStudents保存失败", 8001);
                }

            }
        } catch (IOException e) {
            return false;
        }
        return true;
    }

    @Override
    public List<EasArcTlsStudents> query(EasArcTlsStudents studentDto, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        EasArcTlsStudentsExample easArcTlsStudentsExample = new EasArcTlsStudentsExample();
        EasArcTlsStudentsExample.Criteria criteria = easArcTlsStudentsExample.createCriteria();
        if ( Objects.nonNull(studentDto) ) {
            if (StringUtils.hasText(studentDto.getStudentName())) {
                criteria.andStudentNameLike("%" + studentDto.getStudentName() + "%");
            }
            if (StringUtils.hasText(studentDto.getStudentNumber())) {
                criteria.andStudentNumberLike("%" + studentDto.getStudentNumber() + "%");
            }
            if (Objects.nonNull(studentDto.getGender())) {
                criteria.andGenderEqualTo(studentDto.getGender());
            }
            if (StringUtils.hasText(studentDto.getStudentIdnumber())) {
                criteria.andStudentIdnumberEqualTo(studentDto.getStudentIdnumber());
            }
            if (StringUtils.hasText(studentDto.getPhone())) {
                criteria.andPhoneLike("%"+studentDto.getPhone() + "% %" + studentDto.getPhone() + "%");
            }
            if (StringUtils.hasText(studentDto.getUniversity())) {
                criteria.andUniversityLike("%" + studentDto.getUniversity() + "%");
            }
            if (StringUtils.hasText(studentDto.getAddress())) {
                criteria.andAddressLike("%" + studentDto.getAddress() + "%");
            }
            if (StringUtils.hasText(studentDto.getEmail())) {
                criteria.andEmailEqualTo(studentDto.getEmail());
            }
            if (Objects.nonNull(studentDto.getEnrollmentDate())) {
                criteria.andEnrollmentDateEqualTo(studentDto.getEnrollmentDate());
            }
        }
        List<EasArcTlsStudents> easArcTlsStudents = easArcTlsStudentsMapper.selectByExample(easArcTlsStudentsExample);
        return easArcTlsStudents;
    }

    @Override
    public boolean update(EasArcTlsStudents studentDto) {
        return easArcTlsStudentsMapper.updateByPrimaryKey(studentDto) == 1;
    }

    @Override
    public boolean delete(int id) {
        return easArcTlsStudentsMapper.deleteByPrimaryKey(id) == 1;
    }

    @Override
    public boolean importExcel(InputStream inputStream) {
        ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        try {
            EasArcTlsStudents easArcTlsStudents = null;
                    List<EasArcTlsStudentsDto> studentList = ExcelImportUtil.importExcel(
                    inputStream, EasArcTlsStudentsDto.class, params);
            for (EasArcTlsStudentsDto studentDto : studentList) {
                easArcTlsStudents = new EasArcTlsStudents();
                BeanUtils.copyProperties(studentDto, easArcTlsStudents);
                add(easArcTlsStudents);
            }
            return true;
        } catch (Exception ignored){
            ignored.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException ignored) {}
            }
        }
        return false;
    }

    private Map<String, Object> generateDataMap(EasArcTlsStudents easArcTlsStudents, String studentNumber) {
        Map<String, Object> map = new HashMap<>();
        map.put("student_name", easArcTlsStudents.getStudentName());
        map.put("gender", convertToGender(easArcTlsStudents.getGender()));
        map.put("major", easArcTlsStudents.getMajor());
        map.put("grade", easArcTlsStudents.getGrade());
        map.put("enrollment_date", DateManager.convertToYearMonthDay(easArcTlsStudents.getEnrollmentDate()));
        map.put("phone", easArcTlsStudents.getPhone());
        map.put("university", easArcTlsStudents.getUniversity());
        map.put("student_idnumber", easArcTlsStudents.getStudentIdnumber());
        map.put("avatar", getClass().getClassLoader().getResourceAsStream(PHOTO_PATH));
        map.put("student_number", studentNumber);
        return map;
    }

    public ArchivesDto insertEasArcArchives(EasArcTlsStudents easArcTlsStudents,  XWPFDocument doc) {
        // 生成档案号
        String archiveCode = ArchiveManager.generateArchiveCode(easArcTlsStudents.getStudentNumber(), String.valueOf(FileType.DOCX.getValue()));

        // 保存学员档案文件
        ArchivesDto archivesDto = easArchivesFilesService.saveArchiveStudentsFile(easArcTlsStudents.getStudentIdnumber(), doc);
        String filePath = archivesDto.getPath();
        String arcType = archivesDto.getFileType();

        // 设置时间和有效期
        Date createTime = DateManager.convertToYearMonthDayToDate(new Date());
        Date modifyTime = new Date();
        Calendar calendar = Calendar.getInstance();
        assert createTime != null;
        calendar.setTime(createTime);
        calendar.add(Calendar.YEAR, 1);
        Date validityTime = calendar.getTime();

        // 创建 EasArcArchives 对象并设置属性
        EasArcArchives easArcArchives = new EasArcArchives();
        easArcArchives.setArchiveNumber(archiveCode);
        easArcArchives.setStudentNumber(easArcTlsStudents.getStudentNumber());
        easArcArchives.setFilePath(filePath);
        easArcArchives.setArctype(arcType);
        easArcArchives.setCreateTime(createTime);
        easArcArchives.setModifyTime(modifyTime);
        easArcArchives.setValidityTime(validityTime);
        easArcArchives.setManagerId(easArcTlsStudents.getManagerId());
        easArcArchives.setCreateUid(SecurityManager.getLoginUid().intValue());
        easArcArchives.setCreateDate(new Date());

        // 插入到数据库
        int result = easArcArchivesMapper.insert(easArcArchives);
        archivesDto.setStatus( result == 1 );
        // 返回是否成功插入数据库
        return archivesDto;
    }


    private boolean insertEasSysStudents(EasArcTlsStudents easArcTlsStudents) {
        EasSysStudent easSysStudents = new EasSysStudent();
        BeanUtils.copyProperties(easArcTlsStudents, easSysStudents);
        //设置初始密码 使用 passwordEncoder 设置初始密码为123456
        easSysStudents.setPasswd(passwordEncoder.encode("123456"));
        easSysStudents.setDisabled("N");
        easSysStudents.setAvatar("占位图片.jpg");
        return easSysStudentMapper.insert(easSysStudents) == 1;
    }

    private boolean insertEasArcTlsStudents(EasArcTlsStudents easArcTlsStudents) {
        //判断是否插入成功 成功的话返回true 不成功的话返回false
        return easArcTlsStudentsMapper.insert(easArcTlsStudents) == 1;
    }

    private String generateStudentNumber(EasArcTlsStudents easArcTlsStudents) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(easArcTlsStudents.getEnrollmentDate());
        String year = String.valueOf(calendar.get(Calendar.YEAR));

        return ArchiveManager.generateStudentCode("",
                easArcTlsStudents.getStudentIdnumber(), easArcTlsStudents.getUniversity(), year);
    }

    private String convertToGender(String gender) {
        return Gender.getkeyByString(gender);
    }

    private void replacePlaceholders(XWPFDocument document, Map<String, Object> map) {
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    String cellText = cell.getText();
                    if (!cellText.contains("${")) {
                        continue;
                    }
                    map.forEach((key, value) -> {
                        String placeholder = "${" + key + "}";
                        if (cellText.contains(placeholder) && Objects.nonNull(value)) {
                            try {
                                cell.removeParagraph(0);
                                if (value instanceof InputStream) {
                                    cell.addParagraph().createRun().addPicture((InputStream) value,
                                            XWPFDocument.PICTURE_TYPE_JPEG, "avatar.jpg",
                                            Units.pixelToEMU(110), Units.pixelToEMU(140));
                                } else {
                                    cell.setText(cellText.replace(placeholder, value.toString()));
                                }
                            } catch (IOException | InvalidFormatException e) {
                                throw new EasException("学员导入失败");

                            }
                        }
                    });
                }
            }
        }
    }
}


