package com.fs.statis.service.impl;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.fs.common.exception.ServiceException;
import com.fs.common.utils.StringUtils;
import com.fs.company.cache.ICompanyUserCacheService;
import com.fs.company.domain.CompanyDept;
import com.fs.company.domain.CompanyUser;
import com.fs.company.mapper.CompanyDeptMapper;
import com.fs.company.mapper.CompanyUserMapper;
import com.fs.course.domain.FsUserCourse;
import com.fs.course.mapper.FsUserCourseMapper;
import com.fs.qw.cache.QwSopCacheService;
import com.fs.qw.cache.QwUserCacheService;
import com.fs.qw.domain.QwUser;
import com.fs.qw.mapper.QwUserMapper;
import com.fs.sop.domain.QwSopLogs;
import com.fs.sop.domain.SopUserLogs;
import com.fs.sop.mapper.*;
import com.fs.statis.domain.*;
import com.fs.statis.dto.StatsWatchLogPageListDTO;
import com.fs.statis.mapper.FsStatisSalerWatchMapper;
import com.fs.statis.mapper.FsStatisTempFsuserMapper;
import com.fs.statis.mapper.FsStatisTempParamMapper;
import com.fs.statis.service.FsStatisSalerWatchService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 销售观看统计服务实现类
 */
@Service("fsStatisSalerWatchService")
@Slf4j
public class FsStatisSalerWatchServiceImpl implements FsStatisSalerWatchService {

    private final FsStatisSalerWatchMapper fsStatisSalerWatchMapper;

    private final CompanyUserMapper companyUserMapper;

    private final QwUserMapper qwUserMapper;

    private final QwSopLogsMapper qwSopLogsMapper;



    private final SopUserLogsMapper sopUserLogsMapper;

    private final CompanyDeptMapper companyDeptMapper;

    private final ICompanyUserCacheService companyUserCacheService;

    @Autowired
    private QwUserCacheService qwUserCacheService;

    @Autowired
    private FsStatisTempParamMapper fsStatisTempParamMapper;
    @Autowired
    private FsStatisTempFsuserMapper fsStatisTempFsuserMapper;

    @Autowired
    private QwSopCacheService qwSopCacheService;

    @Autowired
    private FsUserCourseMapper fsUserCourseMapper;

    @Autowired
    public FsStatisSalerWatchServiceImpl(FsStatisSalerWatchMapper fsStatisSalerWatchMapper,
                                         CompanyUserMapper companyUserMapper,
                                         QwUserMapper qwUserMapper,
                                         QwSopLogsMapper qwSopLogsMapper,
                                         SopUserLogsMapper sopUserLogsMapper,
                                         CompanyDeptMapper companyDeptMapper,
                                         ICompanyUserCacheService companyUserCacheService) {
        this.fsStatisSalerWatchMapper = fsStatisSalerWatchMapper;
        this.companyUserMapper = companyUserMapper;
        this.qwUserMapper = qwUserMapper;
        this.qwSopLogsMapper = qwSopLogsMapper;
        this.sopUserLogsMapper = sopUserLogsMapper;
        this.companyDeptMapper = companyDeptMapper;
        this.companyUserCacheService = companyUserCacheService;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FsStatisSalerWatch getById(Integer id) {
        if (id == null) {
            return null;
        }
        return fsStatisSalerWatchMapper.findById(id);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<FsStatisSalerWatch> getAll() {
        return fsStatisSalerWatchMapper.findAll();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FsStatisSalerWatch create(FsStatisSalerWatch fsStatisSalerWatch) {
        if (fsStatisSalerWatch == null) {
            return null;
        }
        fsStatisSalerWatch.setId(null);
        fsStatisSalerWatchMapper.insert(fsStatisSalerWatch);
        return fsStatisSalerWatch;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FsStatisSalerWatch update(FsStatisSalerWatch fsStatisSalerWatch) {
        if (fsStatisSalerWatch == null || fsStatisSalerWatch.getId() == null) {
            return null;
        }
        int affectedRows = fsStatisSalerWatchMapper.update(fsStatisSalerWatch);
        if (affectedRows > 0) {
            return fsStatisSalerWatch;
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean deleteById(Integer id) {
        if (id == null) {
            return false;
        }
        int affectedRows = fsStatisSalerWatchMapper.deleteById(id);
        return affectedRows > 0;
    }

    @Override
    public List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param) {
        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
            return Collections.emptyList();
        }
        List<FsStatisSalerWatch> fsStatisSalerWatches;
        if (needWatchLogQuery(param)) {
            if (!prepareCourseIds(param)) {
                return Collections.emptyList();
            }
            fsStatisSalerWatches = fsStatisSalerWatchMapper.queryListByWatchLog(param);
        } else {
            fsStatisSalerWatches = fsStatisSalerWatchMapper.queryList(param);
        }
        fillUserAndDeptName(fsStatisSalerWatches);
        return fsStatisSalerWatches;
    }

    @Override
    public List<FsStatisSalerWatch> queryPeriodList(StatsWatchLogPageListDTO param) {
        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
            return Collections.emptyList();
        }
        List<FsStatisSalerWatch> fsStatisSalerWatches = fsStatisSalerWatchMapper.queryPeriodList(param);
        for (FsStatisSalerWatch item : fsStatisSalerWatches) {
            if(item.getDeptId() != null) {
                CompanyDept companyDept = companyDeptMapper.selectCompanyDeptById(item.getDeptId());
                if(ObjectUtils.isNotNull(companyDept)) {
                    item.setDeptName(companyDept.getDeptName());
                }
            }
            if(item.getCompanyUserId() != null) {
                String companyUserName = companyUserCacheService.selectCompanyUserNameUserById(item.getCompanyUserId());
                if(StringUtils.isNotEmpty(companyUserName)){
                    item.setCompanyUserName(companyUserName);
                }
            }

            if(item.getPeriodId() != null) {
                String qwSopLogNameBySopId = qwSopCacheService.getQwSopLogNameBySopId(item.getPeriodId());
                if(StringUtils.isNotEmpty(qwSopLogNameBySopId)) {
                    item.setPeriodName(qwSopLogNameBySopId);
                }
            }

            if(item.getSopId() != null) {
                String qwSopNameBySopId = qwSopCacheService.getQwSopNameBySopId(item.getSopId());
                if(StringUtils.isNotEmpty(qwSopNameBySopId)) {
                    item.setSopTaskName(qwSopNameBySopId);
                }
            }
        }
        return fsStatisSalerWatches;
    }

    @Override
    public List<FsStatisSalerWatch> queryTodayList(StatsWatchLogPageListDTO param) {
        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
            return Collections.emptyList();
        }
        List<FsStatisSalerWatch> fsStatisSalerWatches = fsStatisSalerWatchMapper.queryTodayList(param);
        for (FsStatisSalerWatch item : fsStatisSalerWatches) {
            if(item.getDeptId() != null) {
                CompanyDept companyDept = companyDeptMapper.selectCompanyDeptById(item.getDeptId());
                if(ObjectUtils.isNotNull(companyDept)) {
                    item.setDeptName(companyDept.getDeptName());
                }
            }
            if(item.getCompanyUserId() != null) {
                String companyUserName = companyUserCacheService.selectCompanyUserNameUserById(item.getCompanyUserId());
                if(StringUtils.isNotEmpty(companyUserName)){
                    item.setCompanyUserName(companyUserName);
                }
            }

            if(item.getPeriodId() != null) {
                String periodName = qwSopLogsMapper.queryPeriodNameById(item.getPeriodId());
                if(StringUtils.isNotEmpty(periodName)) {
                    item.setPeriodName(periodName);
                }
            }

        }
        return fsStatisSalerWatches;
    }

    @Override
    public List<FsStatisSalerWatch> export(StatsWatchLogPageListDTO param) {
        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
            return Collections.emptyList();
        }
        if (needWatchLogQuery(param)) {
            if (!prepareCourseIds(param)) {
                return Collections.emptyList();
            }
            return fsStatisSalerWatchMapper.queryListExportByWatchLog(param);
        }
        return fsStatisSalerWatchMapper.queryListExport(param);
    }

    /**
     * 是否走看课日志实时聚合（项目或课程区间）
     */
    private boolean needWatchLogQuery(StatsWatchLogPageListDTO param) {
        if (param == null) {
            return false;
        }
        if (param.getProject() != null) {
            return true;
        }
        return param.getCourseStart() != null || param.getCourseEnd() != null;
    }

    /**
     * 解析项目下课程 ID：按 sort 升序，空 sort 靠后；有区间则按下标切片（1-based）
     * @return false 表示应返回空列表（无匹配课程）
     */
    private boolean prepareCourseIds(StatsWatchLogPageListDTO param) {
        if (param.getCourseStart() != null || param.getCourseEnd() != null) {
            if (param.getProject() == null) {
                throw new ServiceException("请先选择项目后再按课程区间筛选");
            }
        }
        if (param.getProject() == null) {
            return false;
        }
        FsUserCourse query = new FsUserCourse();
        query.setProject(param.getProject());
        query.setIsDel(0);
        List<FsUserCourse> courses = fsUserCourseMapper.selectFsUserCourseList(query);
        if (CollectionUtils.isEmpty(courses)) {
            param.setCourseIds(Collections.emptyList());
            return false;
        }
        courses.sort(Comparator
                .comparing((FsUserCourse c) -> c.getSort() == null)
                .thenComparing(c -> c.getSort() == null ? 0L : c.getSort())
                .thenComparing(c -> c.getCourseId() == null ? 0L : c.getCourseId()));
        int from = param.getCourseStart() == null ? 1 : param.getCourseStart();
        int to = param.getCourseEnd() == null ? courses.size() : param.getCourseEnd();
        if (from < 1) {
            from = 1;
        }
        if (to < from) {
            throw new ServiceException("课程区间起始不能大于结束");
        }
        if (from > courses.size()) {
            param.setCourseIds(Collections.emptyList());
            return false;
        }
        if (to > courses.size()) {
            to = courses.size();
        }
        List<Long> courseIds = new ArrayList<>();
        for (int i = from - 1; i < to; i++) {
            Long courseId = courses.get(i).getCourseId();
            if (courseId != null) {
                courseIds.add(courseId);
            }
        }
        if (courseIds.isEmpty()) {
            param.setCourseIds(Collections.emptyList());
            return false;
        }
        param.setCourseIds(courseIds);
        return true;
    }

    /**
     * 补齐部门名、销售昵称
     */
    private void fillUserAndDeptName(List<FsStatisSalerWatch> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        for (FsStatisSalerWatch item : list) {
            if (item.getDeptId() != null) {
                CompanyDept companyDept = companyDeptMapper.selectCompanyDeptById(item.getDeptId());
                if (ObjectUtils.isNotNull(companyDept)) {
                    item.setDeptName(companyDept.getDeptName());
                }
            }
            if (item.getCompanyUserId() != null) {
                String companyUserName = companyUserCacheService.selectCompanyUserNameUserById(item.getCompanyUserId());
                if (StringUtils.isNotEmpty(companyUserName)) {
                    item.setCompanyUserName(companyUserName);
                }
            }
        }
    }

    @Override
    public List<FsStatisSopWatch> exportQueryPeriodList(StatsWatchLogPageListDTO param) {
        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
            return Collections.emptyList();
        }
        List<FsStatisSopWatch> fsStatisSopWatches = fsStatisSalerWatchMapper.queryPeriodListExport(param);
        Map<String, QwSopLogs> stringQwSopLogsMap = qwSopLogsMapper.queryAllPeriod();

        for (FsStatisSopWatch item : fsStatisSopWatches) {
            if(item.getPeriodId() != null) {
                QwSopLogs qwSopLogs = stringQwSopLogsMap.get(item.getPeriodId());
                if(qwSopLogs != null) {
                    item.setPeriodName(qwSopLogs.getSopTitle());
                }
            } else {
                item.setPeriodName("空营期");
            }
        }
        return fsStatisSopWatches;
    }

    @Override
    public List<FsStatisEveryDayWatch> exportQueryEveryDayList(StatsWatchLogPageListDTO param) {
        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
            return Collections.emptyList();
        }
        return fsStatisSalerWatchMapper.queryEveryDayListExport(param);
    }


    @Override
    public synchronized void writeData(String date) {

        // 统计销售看课情况
        // 获取前一天的时间
        List<CompanyUser> companyUserList = this.companyUserMapper.selectAllCompanyUserList();
        // 查询所有符合条件的 SOP 用户日志
        List<SopUserLogs> allSopUserLogs = sopUserLogsMapper.queryAllSopUserLogs();

        Map<String, List<SopUserLogs>> qwUserIdToIdsMap = allSopUserLogs.stream()
                .filter(Objects::nonNull)
                .filter(log -> log.getQwUserId() != null && log.getId() != null)
                .collect(Collectors.groupingBy(SopUserLogs::getQwUserId));

        qwUserCacheService.initCache();

        Map<Long, List<String>> qwUserIdMap = queryQwListMap();

        LocalDate previousDay = LocalDate.now().minusDays(1);
        if(date != null) {
            previousDay = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }

        List<FsStatisTempParam> list = new ArrayList<>();
        for (CompanyUser companyUser : companyUserList) {

            if(companyUser.getCompanyId() == null) {
                log.info("销售{} 对应公司id {} 为空！",companyUser.getUserId(),companyUser.getCompanyId());
                continue;
            }
            // 找到销售关联的 企微账号
            List<String> qwUserIdList = qwUserIdMap.get(companyUser.getUserId());
            if(CollectionUtils.isEmpty(qwUserIdList)){
                log.info("当前销售 {} 没有关联企微账号！",companyUser.getUserId());
                continue;
            }

            // 确定当前销售对应的sop任务的执行记录
            List<SopUserLogs> periodList = getPeriodListByQwUserIds(allSopUserLogs,qwUserIdToIdsMap,qwUserIdList);

            if(CollectionUtils.isEmpty(periodList)){
                log.info("当前销售 {} 没有相关的SOP营期！", companyUser.getUserId());
                continue;
            }


            for (SopUserLogs sopUserLogs : periodList) {

                String periodId = sopUserLogs.getId();
                String sopId = sopUserLogs.getSopId();
                String startTime = sopUserLogs.getStartTime();

                FsStatisTempParam param = new FsStatisTempParam();

                param.setCompanyUserId(companyUser.getUserId());
                param.setSopId(sopId);
                param.setThisDate(previousDay);
                param.setStartTime(startTime);
                String qwUserId = qwUserCacheService.getIdByQwUserIdAndCorpId(sopUserLogs.getQwUserId(), sopUserLogs.getCorpId());

                param.setQwUserId(qwUserId);
                param.setPeriodId(periodId);
                param.setDeptId(companyUser.getDeptId());
                list.add(param);
            }
        }

        // --------清空临时表----------
        fsStatisTempParamMapper.clearSop();
        fsStatisTempFsuserMapper.clear();
        fsStatisTempParamMapper.clear();

        // 删除之前的数据
        fsStatisSalerWatchMapper.deleteDateData(date);

        // -------开始计算-------------
        fsStatisTempParamMapper.batchSave(list);
        fsStatisTempParamMapper.batchSaveToSop(list);

        log.info("list 大小{}",list.size());

        // 根据临时表生成数据
        fsStatisSalerWatchMapper.generateData(date);

        // 写入企微重粉数和看课重粉数临时表
        List<FsStatisTempFsuser> tempData = fsStatisSalerWatchMapper.querySopRepeatData(date);
        if (tempData != null && !tempData.isEmpty()) {
            fsStatisTempFsuserMapper.insertBatch(tempData);
        }
        // 生成企微重粉数和看课重粉数
        fsStatisSalerWatchMapper.generateSopData(date);
        // 清空临时表
        fsStatisTempFsuserMapper.clear();
        fsStatisTempParamMapper.clear();
        fsStatisTempParamMapper.clearSop();
    }

    @Override
    public void writeData() {
        // 统计销售看课情况
        // 获取前一天的时间
        List<CompanyUser> companyUserList = this.companyUserMapper.selectAllCompanyUserList();

        List<FsStatisSalerWatch> writeData = new ArrayList<>();

        LocalDate previousDay = LocalDate.now().minusDays(1);
        for (CompanyUser companyUser : companyUserList) {

            if(companyUser.getCompanyId() == null) {
                log.info("销售{} 对应公司id {} 为空！",companyUser.getUserId(),companyUser.getCompanyId());
                continue;
            }
            // 找到销售关联的 企微账号
            List<String> qwUserIdList = qwUserMapper.findQwUserIdListByCompanyUserId(companyUser.getUserId());
            if(CollectionUtils.isEmpty(qwUserIdList)){
                log.info("当前销售 {} 没有关联企微账号！",companyUser.getUserId());
                continue;
            }

            // 确定当前销售对应的sop任务的执行记录
            List<String> periodList = sopUserLogsMapper.selectSopUserLogsByQwUserIds(qwUserIdList);

            if(CollectionUtils.isEmpty(periodList)){
                log.info("当前销售 {} 没有相关的SOP营期！", companyUser.getUserId());
                continue;
            }

            for (String periodId : periodList) {
                // 去sop记录表找对应的SOP发送记录，记录数作为营期人数
                Long periodCount = qwSopLogsMapper.selectQwSopLogsCountByQwUserId(qwUserIdList,periodId,previousDay);
                // 再去course_watch_log找对应的销售观看记录作为已报名数
                Long registerCount = companyUserMapper.queryCompanyUserWatchCount(companyUser.getUserId(),previousDay);
                Long completedCount = companyUserMapper.queryCompanyUserWatchCountCompleted(companyUser.getUserId(),previousDay);
                // 当前销售当天的看课中断数量
                Long interruptCount = companyUserMapper.queryCompanyUserInterruptCount(companyUser.getUserId(),previousDay);

                FsStatisSalerWatch fsStatisSalerWatch = new FsStatisSalerWatch();
                fsStatisSalerWatch.setDeptId(companyUser.getDeptId());
                fsStatisSalerWatch.setCompanyUserId(companyUser.getUserId());
                fsStatisSalerWatch.setTrainCampNum(periodCount);
                fsStatisSalerWatch.setNotRegisteredNum(Math.max(0, periodCount - registerCount));
                fsStatisSalerWatch.setRegisteredNum(registerCount);
                fsStatisSalerWatch.setCompletedNum(completedCount);
                fsStatisSalerWatch.setInterruptNum(interruptCount);

                // 修复比率计算
                float regRate = (periodCount > 0) ? (float) registerCount / periodCount : 0.0f;
                float finishedRate = (registerCount > 0) ? (float) completedCount / registerCount : 0.0f;

                fsStatisSalerWatch.setRegRate(regRate);
                fsStatisSalerWatch.setFinishedRate(finishedRate);
                fsStatisSalerWatch.setDataDate(previousDay);

                fsStatisSalerWatch.setPeriodId(periodId);

                writeData.add(fsStatisSalerWatch);
            }
        }

        if(CollectionUtils.isNotEmpty(writeData)){
            fsStatisSalerWatchMapper.batchSave(writeData);
        }
    }

    // 根据企微号查询SOP营期
    public List<SopUserLogs> getPeriodListByQwUserIds(List<SopUserLogs> allSopUserLogs,
                                                 Map<String, List<SopUserLogs>> qwUserIdToIdsMap
            ,List<String> qwUserIdList) {
        if (CollectionUtils.isEmpty(allSopUserLogs) || CollectionUtils.isEmpty(qwUserIdList)) {
            return new ArrayList<>();
        }

        return qwUserIdList.stream()
                .filter(Objects::nonNull)
                .map(qwUserIdToIdsMap::get)
                .filter(Objects::nonNull)
                .flatMap(List::stream)
                .collect(Collectors.toList());
    }

    private Map<Long,List<String>> queryQwListMap(){
        List<QwUser> qwUsers = qwUserMapper.selectQwUserAllList();
        if(CollectionUtils.isEmpty(qwUsers)){
            return Maps.newHashMap();
        }

        return qwUsers.stream()
                .filter(Objects::nonNull)
                .filter(user -> user.getCompanyUserId() != null && user.getQwUserId() != null)
                .collect(Collectors.groupingBy(
                        QwUser::getCompanyUserId,
                        Collectors.mapping(QwUser::getQwUserId, Collectors.toList())
                ));
    }

    private Map<String,List<Long>> queryQwIdMap(){
        List<QwUser> qwUsers = qwUserMapper.selectQwUserAllList();
        if(CollectionUtils.isEmpty(qwUsers)){
            return Maps.newHashMap();
        }

        return qwUsers.stream()
                .filter(Objects::nonNull)
                .filter(user -> user.getId() != null && user.getQwUserId() != null)
                .collect(Collectors.groupingBy(
                        QwUser::getQwUserId,
                        Collectors.mapping(QwUser::getId, Collectors.toList())
                ));

    }


    @Override
    public void writeDataToday() {
        LocalDate now = LocalDate.now();

        this.writeData(now.toString());
    }
}
