package com.hotwj.platform.reportStatistics.provider.security;

import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hotwj.platform.config.courseResource.domain.bo.HotCourseResourceBo;
import com.hotwj.platform.config.courseResource.domain.vo.HotCourseResourceVo;
import com.hotwj.platform.config.courseResource.service.IHotCourseResourceService;
import com.hotwj.platform.config.mediaResource.domain.HotMediaResource;
import com.hotwj.platform.config.mediaResource.mapper.HotMediaResourceMapper;
import com.hotwj.platform.reportStatistics.domain.vo.OnlineTrainingMonthlyRowVo;
import com.hotwj.platform.reportStatistics.domain.vo.security.OnlineTrainingMonthlyRow;
import com.hotwj.platform.reportStatistics.mapper.LedgerReportMapper;
import com.hotwj.platform.reportStatistics.service.IReportDataProvider;
import com.hotwj.platform.resourceManagement.company.domain.vo.SysCompanyVo;
import com.hotwj.platform.resourceManagement.company.service.ISysCompanyService;
import com.hotwj.platform.securityManagement.training.domain.vo.HotTrainingVo;
import com.hotwj.platform.securityManagement.training.service.IHotTrainingService;
import com.hotwj.platform.securityManagement.trainingCourseConfig.domain.bo.HotTrainingCourseConfigBo;
import com.hotwj.platform.securityManagement.trainingCourseConfig.domain.vo.HotTrainingCourseConfigVo;
import com.hotwj.platform.securityManagement.trainingCourseConfig.service.IHotTrainingCourseConfigService;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.vo.TrainingParticipantStatVo;
import com.hotwj.platform.securityManagement.trainingParticipant.service.IHotTrainingParticipantService;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.service.OssService;
import org.dromara.common.core.utils.StringUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class TrainingPlanMonthlyStatProvider implements IReportDataProvider {

    private final IHotTrainingService trainingService;
    private final ISysCompanyService sysCompanyService;
    private final LedgerReportMapper ledgerReportMapper;
    private final OssService ossService;
    private final IHotTrainingParticipantService hotTrainingParticipantService;
    private final IHotTrainingCourseConfigService hotTrainingCourseConfigService;
    private final IHotCourseResourceService hotCourseResourceService;
    private final HotMediaResourceMapper hotMediaResourceMapper;

    @Override
    public String getTemplateCode() {
        return "templates/securityManage/onlineEducationMonthlyStatistics.html.vm";
    }

    @Override
    public String getReportTitle() {
        return "线上教育培训月度统计表";
    }

    @Override
    public Map<String, Object> prepareData(Map<String, Object> params) {
        Map<String, Object> ctx = initContext(params);
        Long companyId = MapUtil.getLong(params, "companyId");
        Long trainingId = MapUtil.getLong(params, "trainingId");
        if (companyId == null || trainingId == null) {
            return ctx;
        }

        HotTrainingVo training = trainingService.queryById(trainingId);
        if (training == null || !Objects.equals(training.getCompanyId(), companyId)) {
            return ctx;
        }

        // 完善培训统计数据
        enrichTrainingStats(trainingId, training);
        ctx.put("training", training);
        putCompanyInfo(ctx, companyId);

        List<String> normalizedUserIds = normalizeUserIds((List<String>) params.get("userIds"));
        // 计算学员学习进度
        Map<String, String> progressMap = hotTrainingParticipantService.calculateProgressBatch(trainingId, companyId, normalizedUserIds);
        ctx.put("trainingCourses", buildTrainingCourses(trainingId));
        ctx.put("trainingContent", buildTrainingContent(trainingId));

        ctx.put("completedCount", training.getCompleteCount() == null ? 0L : training.getCompleteCount());
        List<OnlineTrainingMonthlyRowVo> voRows = ledgerReportMapper.selectOnlineTrainingMonthlyRows(companyId, trainingId, normalizedUserIds);
        if (voRows == null || voRows.isEmpty()) {
            return ctx;
        }

        ctx.put("rows", buildRows(voRows, progressMap));
        return ctx;
    }

    private Map<String, Object> initContext(Map<String, Object> params) {
        Map<String, Object> ctx = new HashMap<>();
        ctx.put("verifyUrl", MapUtil.getStr(params, "verifyUrl"));
        ctx.put("verifyQrBase64", MapUtil.getStr(params, "verifyQrBase64"));
        return ctx;
    }

    private void enrichTrainingStats(Long trainingId, HotTrainingVo training) {
        List<TrainingParticipantStatVo> stats = hotTrainingParticipantService.queryTrainingParticipantStats(List.of(trainingId));
        if (stats != null && !stats.isEmpty()) {
            TrainingParticipantStatVo stat = stats.get(0);
            training.setTotalCount(stat.getTotalCount());
            training.setPassedCount(stat.getPassedCount());
            training.setIncompleteCount(stat.getIncompleteCount());
            training.setCompleteCount(stat.getCompleteCount());
            training.setPendingReviewCount(stat.getPendingReviewCount());
            return;
        }
        training.setTotalCount(0L);
        training.setPassedCount(0L);
        training.setCompleteCount(0L);
        training.setIncompleteCount(0L);
        training.setPendingReviewCount(0L);
    }

    private void putCompanyInfo(Map<String, Object> ctx, Long companyId) {
        SysCompanyVo company = sysCompanyService.queryById(companyId);
        String companyName = "";
        String responsibleName = "";
        if (company != null) {
            companyName = StringUtils.blankToDefault(company.getCompanyName(), "");
            responsibleName = StringUtils.blankToDefault(company.getResponsibleName(), "");
        }
        ctx.put("companyName", companyName);
        ctx.put("responsibleName", responsibleName);
    }

    private List<String> normalizeUserIds(List<String> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            return null;
        }
        LinkedHashSet<String> set = new LinkedHashSet<>();
        for (String id : userIds) {
            String t = id == null ? "" : id.trim();
            if (!t.isEmpty()) {
                set.add(t);
            }
        }
        if (set.isEmpty()) {
            return null;
        }
        return new ArrayList<>(set);
    }

    private List<Map<String, Object>> buildTrainingCourses(Long trainingId) {
        HotTrainingCourseConfigBo courseConfigBo = new HotTrainingCourseConfigBo();
        courseConfigBo.setTrainingId(trainingId);
        List<HotTrainingCourseConfigVo> courseConfigs = hotTrainingCourseConfigService.queryList(courseConfigBo);
        if (courseConfigs == null || courseConfigs.isEmpty()) {
            return List.of();
        }

        List<Map<String, Object>> items = new ArrayList<>(courseConfigs.size());
        int idx = 1;
        for (HotTrainingCourseConfigVo c : courseConfigs) {
            Map<String, Object> item = new HashMap<>();
            item.put("index", idx++);
            item.put("courseName", StringUtils.blankToDefault(c.getCourseName(), ""));
            item.put("durationMin", getCourseVideoMinutes(c.getCourseId()));
            items.add(item);
        }
        return items;
    }

    private long getCourseVideoMinutes(Long courseId) {
        if (courseId == null) {
            return 0L;
        }
        HotCourseResourceBo resourceBo = new HotCourseResourceBo();
        resourceBo.setCourseId(courseId);
        resourceBo.setResourceType(1L);
        List<HotCourseResourceVo> resources = hotCourseResourceService.queryList(resourceBo);
        if (resources == null || resources.isEmpty()) {
            return 0L;
        }

        List<Long> mediaIds = resources.stream()
                .map(HotCourseResourceVo::getResourceId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (mediaIds.isEmpty()) {
            return 0L;
        }

        long seconds = hotMediaResourceMapper.selectList(
                        Wrappers.<HotMediaResource>lambdaQuery()
                                .select(HotMediaResource::getDurationSeconds)
                                .in(HotMediaResource::getId, mediaIds)
                                .eq(HotMediaResource::getIsDeleted, 0L)
                ).stream()
                .map(HotMediaResource::getDurationSeconds)
                .filter(Objects::nonNull)
                .mapToLong(Long::longValue)
                .sum();
        return (seconds + 59) / 60;
    }

    private String buildTrainingContent(Long trainingId) {
        List<String> courseNames = ledgerReportMapper.selectGovSafetyEducationTrainingCourseNames(trainingId);
        if (courseNames == null || courseNames.isEmpty()) {
            return "";
        }
        return courseNames.stream()
                .filter(Objects::nonNull)
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.joining("\n"));
    }

    private long countCompleted(List<OnlineTrainingMonthlyRowVo> rows) {
        return rows.stream().filter(r -> r.getCompleteTime() != null).count();
    }

    private List<OnlineTrainingMonthlyRow> buildRows(List<OnlineTrainingMonthlyRowVo> voRows, Map<String, String> progressMap) {
        List<OnlineTrainingMonthlyRow> rows = new ArrayList<>(voRows.size());
        for (OnlineTrainingMonthlyRowVo vo : voRows) {
            OnlineTrainingMonthlyRow row = new OnlineTrainingMonthlyRow();
            row.setIndex(vo.getIndex() != null ? vo.getIndex() : 0);
            row.setUserName(StringUtils.blankToDefault(vo.getUserName(), ""));
            row.setPlateNumber(StringUtils.blankToDefault(vo.getPlateNumber(), ""));
            row.setProgressLabel(StringUtils.blankToDefault(vo.getProgressLabel(), ""));
            row.setPhone(StringUtils.blankToDefault(vo.getPhone(), ""));
            row.setPhotoUrl(extractPhotoUrl(vo.getPhotoUrl()));
            row.setSignatureUrl(extractSignatureUrl(vo.getSignatureUrl()));
            row.setExamStatus(StringUtils.blankToDefault(vo.getExamStatus(), ""));
            rows.add(row);
        }
        return rows;
    }


    private String extractPhotoUrl(String raw) {
        if (StringUtils.isBlank(raw)) {
            return "";
        }
        try {
            JSONObject json = JSONUtil.parseObj(raw);
            if (!json.isEmpty()) {
                Object[] values = json.values().toArray();
                if (values.length > 0) {
                    String lastOssId = String.valueOf(values[values.length - 1]);
                    String resolved = resolveMaybeOssUrl(lastOssId);
                    return resolved == null ? "" : resolved;
                }
            }
        } catch (Exception ignored) {
        }
        String resolved = resolveMaybeOssUrl(raw);
        return resolved == null ? "" : resolved;
    }

    private String extractSignatureUrl(String raw) {
        if (StringUtils.isBlank(raw)) {
            return "";
        }
        String resolved = resolveMaybeOssUrl(raw);
        return resolved == null ? "" : resolved;
    }

    private String resolveMaybeOssUrl(String value) {
        if (StringUtils.isBlank(value)) {
            return null;
        }
        String first = value.split(",")[0].trim();
        if (StringUtils.isBlank(first)) {
            return null;
        }
        if (first.startsWith("http")) {
            return first;
        }
        if (first.matches("^\\d+$")) {
            String urls = ossService.selectUrlByIds(first);
            if (StringUtils.isBlank(urls)) {
                return null;
            }
            return urls.split(",")[0].trim();
        }
        return first;
    }
}
