package com.qmth.exam.reserve.template.execute;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.qmth.boot.core.fss.store.FileStore;
import com.qmth.exam.reserve.bean.Constants;
import com.qmth.exam.reserve.entity.AsyncTaskEntity;
import com.qmth.exam.reserve.entity.StudentEntity;
import com.qmth.exam.reserve.enums.AsyncTaskResult;
import com.qmth.exam.reserve.enums.AsyncTaskStatus;
import com.qmth.exam.reserve.enums.FileUploadType;
import com.qmth.exam.reserve.service.AsyncTaskService;
import com.qmth.exam.reserve.service.StudentService;
import com.qmth.exam.reserve.template.upload.AsyncUploadTaskTemplate;
import com.qmth.exam.reserve.util.DateUtil;
import com.qmth.exam.reserve.util.FileUtil;
import com.qmth.exam.reserve.util.ZipUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.util.*;

@Service
public class StudentPhotoUploadService extends AsyncUploadTaskTemplate {

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

    public static final String OBJ_TITLE = "考生照片";

    @Autowired
    private AsyncTaskService asyncTaskService;

    @Autowired
    private FileStore fileStore;

    @Autowired
    private StudentService studentService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadTask(Map<String, Object> map, File file) {
        AsyncTaskEntity task = (AsyncTaskEntity) map.get(Constants.ASYNC_TASK);
        StringJoiner summary = new StringJoiner("\n").add(
                MessageFormat.format("{0}{1}{2}", DateFormatUtils.format(new Date(), DateUtil.LongDateString), BEGIN_TITLE, OBJ_TITLE));
        task.setStatus(AsyncTaskStatus.RUNNING);
        task.setSummary(summary.toString());
        asyncTaskService.updateById(task);

        int num = 0;
        File dirFile = null;
        try {
            dirFile = FileUtil.getDir("studentPhoto" + DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"));
            if (dirFile == null) {
                log.error("[考生头像上传] 临时目录创建失败");
                return;
            }

            ZipUtil.unzip(file, dirFile.getAbsolutePath());
            File[] files = dirFile.listFiles();
            summary.add(MessageFormat.format("{0}{1}{2}", "共有", files != null ? files.length : 0, FINISH_SIZE));

            List<StudentEntity> studentList;
            StringJoiner stringJoiner = FileUtil.getDirName(FileUploadType.UPLOAD, true);
            String path = stringJoiner.toString().replaceAll("\\\\", "/");
            Long taskId = Long.parseLong(map.get("taskId").toString());

            for (File photo : Objects.requireNonNull(files)) {
                String identityNumber = FilenameUtils.getBaseName(photo.getName());
                studentList = listStudentByIdentityNumber(identityNumber, taskId);
                if (CollectionUtils.isEmpty(studentList)) {
                    log.warn("[考生头像上传] 无法找到考生,证件号码:{}", identityNumber);
                    summary.add(MessageFormat.format("{0}{1}", "无法找到考生,证件号码:", identityNumber));
                    continue;
                }
                fileStore.write(path + photo.getName(), Files.newInputStream(photo.toPath()), DigestUtils.md5Hex(Files.newInputStream(photo.toPath())));
                //更新考生的头像
                updateStudentPhoto(studentList,  path + photo.getName());
                num++;
            }

            task.setResult(AsyncTaskResult.SUCCESS);

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            task.setResult(AsyncTaskResult.ERROR);
            summary.add(MessageFormat.format("{0}{1}{2}{3}", DateFormatUtils.format(new Date(), DateUtil.LongDateString),
                    EXCEPTION_CREATE_TXT_TITLE, EXCEPTION_DATA, e.getMessage()));
            task.setSummary(summary.toString());
        } finally {
            //删除临时文件
            deleteTempFile(file, dirFile);
            summary.add(MessageFormat.format("{0}{1}{2}", FINISH_TITLE, num, FINISH_SIZE));
            task.setSummary(summary.toString());
            task.setStatus(AsyncTaskStatus.FINISH);
            asyncTaskService.updateById(task);
        }

    }

    private void deleteTempFile(File tempFile, File dirFile) {
        boolean deleted;
        if (tempFile != null && tempFile.exists()) {
            deleted = tempFile.delete();
            if (!deleted) {
                log.warn("[考生头像上传] 临时文件删除失败,文件:{}", tempFile.getAbsolutePath());
            }
        }
        if (dirFile != null && dirFile.exists()) {
            File[] listFiles = dirFile.listFiles();
            if (listFiles != null) {
                for (File toDeletePhoto : listFiles) {
                    deleted = toDeletePhoto.delete();
                    if (!deleted) {
                        log.warn("[考生头像上传] 删除文件失败,文件:{}", toDeletePhoto.getAbsolutePath());
                    }
                }
            }
            deleted = dirFile.delete();
            if (!deleted) {
                log.warn("[考生头像上传] 删除目录失败,目录:{}", dirFile.getAbsolutePath());
            }
        }
    }

    private void updateStudentPhoto(List<StudentEntity> studentList, String path) {
        LambdaUpdateWrapper<StudentEntity> updateWrapper;
        for (StudentEntity studentEntity : studentList) {
            updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(StudentEntity::getPhotoPath, path);
            updateWrapper.eq(StudentEntity::getId, studentEntity.getId());
            studentService.update(null, updateWrapper);
        }
    }

    private List<StudentEntity> listStudentByIdentityNumber(String identityNumber, Long taskId) {
        LambdaQueryWrapper<StudentEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StudentEntity::getIdentityNumber, identityNumber.trim());
        queryWrapper.eq(StudentEntity::getApplyTaskId, taskId);
        return studentService.list(queryWrapper);
    }
}
