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.driverManagement.driver.domain.vo.HotDriverVo;
import com.hotwj.platform.driverManagement.driver.service.IHotDriverService;
import com.hotwj.platform.reportStatistics.domain.vo.security.StudyRecordCourseVo;
import com.hotwj.platform.reportStatistics.domain.vo.security.StudyRecordData;
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.trainingCourseRecord.domain.bo.HotTrainingCourseRecordBo;
import com.hotwj.platform.securityManagement.trainingCourseRecord.domain.vo.HotTrainingCourseRecordVo;
import com.hotwj.platform.securityManagement.trainingCourseRecord.service.IHotTrainingCourseRecordService;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.bo.HotTrainingParticipantBo;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.vo.HotTrainingParticipantVo;
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 StudyRecordProvider implements IReportDataProvider {

    private final IHotTrainingService trainingService;
    private final ISysCompanyService sysCompanyService;
    private final IHotTrainingParticipantService trainingParticipantService;
    private final LedgerReportMapper ledgerReportMapper;
    private final OssService ossService;
    private final IHotDriverService driverService;
    private final IHotTrainingCourseConfigService trainingCourseConfigService;
    private final IHotCourseResourceService courseResourceService;
    private final HotMediaResourceMapper mediaResourceMapper;
    private final IHotTrainingCourseRecordService trainingCourseRecordService;

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

    @Override
    public String getReportTitle() {
        return "学习记录表";
    }

    @Override
    public String getReportTitle(Map<String, Object> params) {
        Long trainingId = MapUtil.getLong(params, "trainingId");
        if (trainingId != null) {
            HotTrainingVo training = trainingService.queryById(trainingId);
            if (training != null) {
                return training.getPlanName() + "——学习记录表";
            }
        }
        return getReportTitle();
    }

    @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");
        String userId = MapUtil.getStr(params, "userId");
        if (companyId == null || trainingId == null || StringUtils.isBlank(userId)) {
            return ctx;
        }

        HotTrainingVo training = trainingService.queryById(trainingId);
        if (training == null) {
            return ctx;
        }

        ctx.put("training", training);
        ctx.put("companyName", getCompanyName(companyId));

        String trainingContent = buildTrainingContent(trainingId);
        StudyRecordData record = buildStudyRecord(companyId, trainingId, userId, trainingContent);
        ctx.put("record", record);
        return ctx;
    }

    private StudyRecordData buildStudyRecord(Long companyId, Long trainingId, String userId, String trainingContent) {
        StudyRecordData record = new StudyRecordData();
        record.setUserId(userId);
        record.setCourseName(trainingContent);

        HotTrainingParticipantVo participant = getTrainingParticipant(companyId, trainingId, userId);
        if (participant != null) {
            record.setUserName(StringUtils.blankToDefault(participant.getUserName(), ""));
            record.setIdCardNo(StringUtils.blankToDefault(participant.getIdCardNo(), ""));
            record.setPhotoUrls(parsePhotoUrls(participant.getStudyPhotoOssId()));
            record.setSignatureUrl(resolveMaybeOssUrl(participant.getSignatureOssId() == null ? null : String.valueOf(participant.getSignatureOssId())));
        } else {
            record.setUserName("");
            record.setIdCardNo("");
            record.setPhotoUrls(List.of());
            record.setSignatureUrl("");
        }

        record.setPlateNumber(getPlateNumber(companyId, userId));

        List<StudyRecordCourseVo> courseList = ledgerReportMapper.selectStudyRecordCourses(companyId, trainingId, userId);
        record.setCourseList(courseList);

        // 获取课程配置时长映射 (ConfigID -> Seconds)
        Map<Long, Long> configDurationMap = getConfigDurationMap(trainingId);

        Integer learnMinutes = computeLearnMinutes(companyId, trainingId, userId, configDurationMap);
        Integer planMinutes = computePlanMinutes(configDurationMap);
        record.setLearnMinutes(learnMinutes);
        record.setPlanMinutes(planMinutes);
        record.setStudyMinutes(learnMinutes);
        return record;
    }

    private Map<Long, Long> getConfigDurationMap(Long trainingId) {
        HotTrainingCourseConfigBo bo = new HotTrainingCourseConfigBo();
        bo.setTrainingId(trainingId);
        List<HotTrainingCourseConfigVo> configs = trainingCourseConfigService.queryList(bo);
        if (configs == null || configs.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<Long, Long> map = new HashMap<>();
        for (HotTrainingCourseConfigVo c : configs) {
            long seconds = calculateCourseVideoSeconds(c.getCourseId());
            map.put(c.getId(), seconds);
        }
        return map;
    }

    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 String getCompanyName(Long companyId) {
        SysCompanyVo company = sysCompanyService.queryById(companyId);
        if (company == null) {
            return "";
        }
        return StringUtils.blankToDefault(company.getCompanyName(), "");
    }

    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 HotTrainingParticipantVo getTrainingParticipant(Long companyId, Long trainingId, String userId) {
        HotTrainingParticipantBo bo = new HotTrainingParticipantBo();
        bo.setCompanyId(companyId);
        bo.setTrainingId(trainingId);
        bo.setUserId(userId);
        bo.setIsDeleted(0L);
        List<HotTrainingParticipantVo> participants = trainingParticipantService.queryList(bo);
        if (participants == null || participants.isEmpty()) {
            return null;
        }
        return participants.get(0);
    }

    private List<String> parsePhotoUrls(String photoJson) {
        if (StringUtils.isBlank(photoJson)) {
            return List.of();
        }
        List<String> urls = new ArrayList<>();
        try {
            JSONObject json = JSONUtil.parseObj(photoJson);
            if (!json.isEmpty()) {
                for (Object val : json.values()) {
                    String url = resolveMaybeOssUrl(String.valueOf(val));
                    if (StringUtils.isNotBlank(url)) {
                        urls.add(url);
                    }
                }
            }
        } catch (Exception e) {
            for (String s : photoJson.split(",")) {
                String url = resolveMaybeOssUrl(s);
                if (StringUtils.isNotBlank(url)) {
                    urls.add(url);
                }
            }
        }
        return urls;
    }

    private String getPlateNumber(Long companyId, String userId) {
        HotDriverVo driver = driverService.queryById(userId);
        if (driver != null && Objects.equals(companyId, driver.getCompanyId())) {
            return StringUtils.blankToDefault(driver.getPlateNumber(), "");
        }
        return "";
    }

    private Integer computeLearnMinutes(Long companyId, Long trainingId, String userId, Map<Long, Long> configDurationMap) {
        HotTrainingCourseRecordBo bo = new HotTrainingCourseRecordBo();
        bo.setCompanyId(companyId);
        bo.setTrainingId(trainingId);
        bo.setUserId(userId);
        bo.setIsDeleted(0L);
        List<HotTrainingCourseRecordVo> records = trainingCourseRecordService.queryList(bo);
        if (records == null || records.isEmpty()) {
            return 0;
        }

        Map<Long, Long> maxByCourse = new HashMap<>();
        for (HotTrainingCourseRecordVo r : records) {
            if (r.getTrainingCourseId() == null || r.getLearnDurationMin() == null) {
                continue;
            }
            maxByCourse.merge(r.getTrainingCourseId(), r.getLearnDurationMin(), Math::max);
        }
        long totalSeconds = 0L;
        for (Map.Entry<Long, Long> entry : maxByCourse.entrySet()) {
            Long configId = entry.getKey();
            Long actualSeconds = entry.getValue();
            if (actualSeconds == null) continue;

            // 获取该课程配置的计划时长（秒）
            Long planSeconds = configDurationMap.getOrDefault(configId, 0L);

            // 取较小值，确保学习时长不大于课程时长
            long cappedSeconds = Math.min(actualSeconds, planSeconds);
            totalSeconds += cappedSeconds;
        }
        // 数据库中存储的learnDurationMin实际上是秒，需要转换为分钟
        long minutes = (long) Math.ceil(totalSeconds / 60.0);
        if (minutes > Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        }
        return (int) minutes;
    }

    private Integer computePlanMinutes(Map<Long, Long> configDurationMap) {
        if (configDurationMap == null || configDurationMap.isEmpty()) {
            return 0;
        }
        long totalSeconds = 0L;
        for (Long seconds : configDurationMap.values()) {
            if (seconds != null) {
                totalSeconds += seconds;
            }
        }
        long minutes = (long) Math.ceil(totalSeconds / 60.0);
        if (minutes > Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        }
        return (int) minutes;
    }

    private long calculateCourseVideoSeconds(Long courseId) {
        if (courseId == null) {
            return 0L;
        }
        HotCourseResourceBo resourceBo = new HotCourseResourceBo();
        resourceBo.setCourseId(courseId);
        resourceBo.setResourceType(1L);
        List<HotCourseResourceVo> resources = courseResourceService.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;
        }

        return mediaResourceMapper.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();
    }

    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;
    }
}
