package cn.com.qmth.examcloud.tool.service.export_student_photo;

import cn.com.qmth.examcloud.tool.config.SysProperty;
import cn.com.qmth.examcloud.tool.entity.TaskEntity;
import cn.com.qmth.examcloud.tool.service.CommonService;
import cn.com.qmth.examcloud.tool.service.TaskService;
import cn.com.qmth.examcloud.tool.service.export_student_photo.vo.StudentVO;
import cn.com.qmth.examcloud.tool.utils.FileHelper;
import cn.com.qmth.examcloud.tool.utils.FssHelper;
import cn.com.qmth.examcloud.tool.utils.HttpHelper;
import cn.com.qmth.examcloud.tool.utils.JsonMapper;
import cn.com.qmth.examcloud.tool.vo.PageInfo;
import cn.com.qmth.examcloud.tool.vo.user.User;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class ExportStudentPhotoTask implements TaskService {

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

    @Autowired
    private SysProperty sysProperty;

    @Autowired
    private CommonService commonService;

    @Override
    public void start(TaskEntity task) {
        // this.execute(loginUser, task);
    }

    public void execute(User loginUser, String exportDir) {
        // List<StudentVO> hasPhotoStudents = this.loadStudentFromUrl(loginUser);
        List<StudentVO> hasPhotoStudents = this.loadStudentFromExcel(exportDir + "/students.xlsx");
        this.downloadImages(hasPhotoStudents, exportDir, false);
    }

    private List<StudentVO> loadStudentFromUrl(User loginUser) {
        long startTime = System.currentTimeMillis();

        final String url = loginUser.getServerUrl() + "/api/ecs_core/student/studentPage/%s/%s?rootOrgId=%s&hasPhoto=TRUE";
        Map<String, String> headers = new HashMap<>();
        headers.put("key", loginUser.getKey());
        headers.put("token", loginUser.getToken());

        long pageNo = 0, pageSize = 100, finishCount = 0, noPhotoCount = 0;
        JsonMapper jsonMapper = new JsonMapper();

        List<StudentVO> hasPhotoStudents = new ArrayList<>();
        while (true) {
            String json = HttpHelper.get(String.format(url, pageNo, pageSize, loginUser.getRootOrgId()), headers, null);
            PageInfo<StudentVO> page = jsonMapper.parseJson(json, new TypeReference<PageInfo<StudentVO>>() {
            });
            if (page == null || CollectionUtils.isEmpty(page.getList())) {
                break;
            }

            for (StudentVO student : page.getList()) {
                if (StringUtils.isEmpty(student.getPhotoPath())) {
                    noPhotoCount++;
                    continue;
                }

                hasPhotoStudents.add(student);
            }

            pageNo++;
            finishCount += page.getList().size();
            float finishRate = finishCount * 100f / page.getTotal();
            long cost = Math.max((System.currentTimeMillis() - startTime) / 1000, 1);
            float speed = (float) finishCount / cost;
            log.info("【获取学生】 总数:{} 已获取数:{} 无底照数:{} 进度:{}% 速度:约{}个每秒 已耗时:{}秒 pageNo:{}",
                    page.getTotal(), finishCount, noPhotoCount, finishRate, speed, cost, pageNo);
        }

        return hasPhotoStudents;
    }

    private List<StudentVO> loadStudentFromExcel(String dataFilePath) {
        /*
            select stu.id, stu.root_org_id 学校ID, stu.name 学生姓名, stu.identity_number 身份证号,
            (select GROUP_CONCAT(DISTINCT sc.student_code) from ec_b_student_code sc where sc.student_id = stu.id)学号,stu.photo_path 照片
            from ec_b_student stu where stu.root_org_id = 0 and stu.photo_path is not null;
        */
        long startTime = System.currentTimeMillis();
        List<StudentVO> list = new ArrayList<>();
        try {
            EasyExcel.read(dataFilePath, StudentVO.class, new AnalysisEventListener<StudentVO>() {
                        @Override
                        public void invoke(StudentVO data, AnalysisContext analysisContext) {
                            list.add(data);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                            // ignore
                        }
                    }
            ).sheet().doRead();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("Excel内容解析错误，请使用标准模板！");
        }

        int noPhotoCount = 0;
        List<StudentVO> hasPhotoStudents = new ArrayList<>();
        for (StudentVO student : list) {
            if (StringUtils.isEmpty(student.getPhotoPath())) {
                noPhotoCount++;
                continue;
            }

            if (StringUtils.isNotBlank(student.getStudentCodesStr())) {
                student.setStudentCodeList(Lists.newArrayList(student.getStudentCodesStr().split(",")));
            }
            hasPhotoStudents.add(student);
        }

        long cost = System.currentTimeMillis() - startTime;
        log.info("【获取学生】 总数:{} 有底照数:{} 无底照数:{} 耗时:{}ms", list.size(), hasPhotoStudents.size(), noPhotoCount, cost);
        return hasPhotoStudents;
    }

    private void downloadImages(List<StudentVO> students, String exportDir, boolean fileNameByStudentCode) {
        long startTime = System.currentTimeMillis();
        int totalCount = students.size();
        AtomicInteger finishCount = new AtomicInteger(), successCount = new AtomicInteger(), failCount = new AtomicInteger();
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (StudentVO student : students) {
            executorService.execute(() -> {
                String photoSuffix = FileHelper.getFileSuffix(student.getPhotoPath());
                if (fileNameByStudentCode) {
                    if (CollectionUtils.isNotEmpty(student.getStudentCodeList())) {
                        if (student.getStudentCodeList().size() > 1) {
                            log.warn("identityNumber:{} 多个学号！{}", student.getIdentityNumber(), student.getStudentCodesStr());
                        }
                        for (String studentCode : student.getStudentCodeList()) {
                            String savePhotoPath = String.format("%s/%s/%s%s", exportDir, student.getRootOrgId(), studentCode, photoSuffix);
                            this.doDownload(student.getPhotoPath(), savePhotoPath, successCount, failCount);
                        }
                    } else {
                        log.warn("identityNumber:{} 无学号！", student.getIdentityNumber());
                        String savePhotoPath = String.format("%s/%s/%s%s", exportDir, student.getRootOrgId(), student.getIdentityNumber(), photoSuffix);
                        this.doDownload(student.getPhotoPath(), savePhotoPath, successCount, failCount);
                    }
                } else {
                    String savePhotoPath = String.format("%s/%s/%s%s", exportDir, student.getRootOrgId(), student.getIdentityNumber(), photoSuffix);
                    this.doDownload(student.getPhotoPath(), savePhotoPath, successCount, failCount);
                }

                finishCount.incrementAndGet();
                if (finishCount.get() % 100 == 0) {
                    float finishRate = finishCount.get() * 100f / totalCount;
                    long cost = Math.max((System.currentTimeMillis() - startTime) / 1000, 1);
                    float speed = (float) finishCount.get() / cost;
                    log.info("【底照下载】 总数:{} 成功数:{} 失败数:{} 进度:{}% 速度:约{}个每秒 已耗时:{}秒",
                            totalCount, successCount.get(), failCount.get(), finishRate, speed, cost);
                }
            });
        }

        // 停止接受新任务，并等待所有任务完成
        executorService.shutdown();
        while (!executorService.isTerminated()) {
            // ignore
        }

        float finishRate = finishCount.get() * 100f / totalCount;
        long cost = Math.max((System.currentTimeMillis() - startTime) / 1000, 1);
        float speed = (float) finishCount.get() / cost;
        log.info("【底照下载】 总数:{} 成功数:{} 失败数:{} 进度:{}% 速度:约{}个每秒 已耗时:{}秒",
                totalCount, successCount.get(), failCount.get(), finishRate, speed, cost);
    }

    private void doDownload(String photoUrl, String photoPath, AtomicInteger successCount, AtomicInteger failCount) {
        // String urlPrefix = "https://ecs-test-static.qmth.com.cn";
        String urlPrefix = "https://ecs-static.qmth.com.cn";
        // String urlPrefix = "https://apply-file.qmth.com.cn";
        photoUrl = FssHelper.finalFileUrl(photoUrl, urlPrefix);

        if (new File(photoPath).exists()) {
            log.debug("【已下载】 {} {}", photoPath, photoUrl);
            successCount.incrementAndGet();
            return;
        }

        try {
            FileHelper.saveImageToFile(photoUrl, photoPath);
            successCount.incrementAndGet();
        } catch (Exception e) {
            log.error("【下载错误】 {} err:{}", photoPath, e.getMessage());
            failCount.incrementAndGet();
        }
    }

}
