package com.fs.course.service.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.fs.common.core.controller.BaseController;
import com.fs.common.core.page.PageDomain;
import com.fs.common.core.page.TableSupport;
import com.fs.common.exception.CustomException;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.DictUtils;
import com.fs.common.utils.date.DateUtil;
import com.fs.common.utils.sql.SqlUtil;
import com.fs.company.cache.ICompanyCacheService;
import com.fs.company.mapper.CompanyDeptMapper;
import com.fs.course.param.FsCourseTrafficLogParam;
import com.fs.course.param.InternetTrafficParam;
import com.fs.course.param.StatisticsSummaryParam;
import com.fs.course.param.TrafficRecord;
import com.fs.course.vo.DeptFullPathVO;
import com.fs.course.vo.FsCourseTrafficLogListVO;
import com.fs.course.vo.StatisticsSummaryVO;
import com.fs.store.service.cache.IFsUserCourseCacheService;
import com.fs.system.domain.SysConfig;
import com.fs.system.service.ISysConfigService;
import com.github.pagehelper.PageHelper;
import com.hc.openapi.tool.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fs.course.mapper.FsCourseTrafficLogMapper;
import com.fs.course.domain.FsCourseTrafficLog;
import com.fs.course.service.IFsCourseTrafficLogService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 短链课程流量记录Service业务层处理
 *
 * @author fs
 * @date 2024-10-31
 */
@Service
@Slf4j
public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
{
    @Autowired
    private FsCourseTrafficLogMapper fsCourseTrafficLogMapper;
    @Autowired
    private ISysConfigService iSysConfigService;
    @Autowired
    private ICompanyCacheService companyCacheService;

    @Autowired
    private IFsUserCourseCacheService fsUserCourseCacheService;

    @Autowired
    CompanyDeptMapper companyDeptMapper;

    /**
     * 查询短链课程流量记录
     *
     * @param logId 短链课程流量记录主键
     * @return 短链课程流量记录
     */
    @Override
    public FsCourseTrafficLog selectFsCourseTrafficLogByLogId(Long logId)
    {
        return fsCourseTrafficLogMapper.selectFsCourseTrafficLogByLogId(logId);
    }

    /**
     * 查询短链课程流量记录列表
     *
     * @param fsCourseTrafficLog 短链课程流量记录
     * @return 短链课程流量记录
     */
    @Override
    public List<FsCourseTrafficLog> selectFsCourseTrafficLogList(FsCourseTrafficLog fsCourseTrafficLog)
    {
        return fsCourseTrafficLogMapper.selectFsCourseTrafficLogList(fsCourseTrafficLog);
    }

    /**
     * 新增短链课程流量记录
     *
     * @param fsCourseTrafficLog 短链课程流量记录
     * @return 结果
     */
    @Override
    public int insertFsCourseTrafficLog(FsCourseTrafficLog fsCourseTrafficLog)
    {
        fsCourseTrafficLog.setCreateTime(DateUtils.getNowDate());
        return fsCourseTrafficLogMapper.insertFsCourseTrafficLog(fsCourseTrafficLog);
    }

    /**
     * 修改短链课程流量记录
     *
     * @param fsCourseTrafficLog 短链课程流量记录
     * @return 结果
     */
    @Override
    public int updateFsCourseTrafficLog(FsCourseTrafficLog fsCourseTrafficLog)
    {
        return fsCourseTrafficLogMapper.updateFsCourseTrafficLog(fsCourseTrafficLog);
    }

    /**
     * 批量删除短链课程流量记录
     *
     * @param logIds 需要删除的短链课程流量记录主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseTrafficLogByLogIds(Long[] logIds)
    {
        return fsCourseTrafficLogMapper.deleteFsCourseTrafficLogByLogIds(logIds);
    }

    /**
     * 删除短链课程流量记录信息
     *
     * @param logId 短链课程流量记录主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseTrafficLogByLogId(Long logId)
    {
        return fsCourseTrafficLogMapper.deleteFsCourseTrafficLogByLogId(logId);
    }

    @Override
    public List<FsCourseTrafficLogListVO> selectTrafficByCompany(FsCourseTrafficLogParam param) {
        return fsCourseTrafficLogMapper.selectTrafficByCompany(param);
    }


    @Override
    public void saveCourseTrafficLog() {
        Integer count = fsCourseTrafficLogMapper.saveCourseTrafficLogByTwoDaysLaterCount();
        Integer limit = 1000;
        log.info("总数: {}", count);

        // Start timing
        long startTime = System.currentTimeMillis();
        log.info("开始处理，时间: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

        // 计算需要查询的次数
        int totalPages = (count + limit - 1) / limit; // 向上取整
        for (int page = 0; page < totalPages; page++) {
            int offset = page * limit;

            log.info("开始查询");
            List<FsCourseTrafficLog> redPacketLogs = fsCourseTrafficLogMapper.selectCourseTrafficLogByTwoDaysLater(0,limit);
            log.info("查询结果: {}", redPacketLogs);
            // 处理当前批次的1000条数据
            if (redPacketLogs==null ||redPacketLogs.isEmpty()) {
                log.info("没有数据");
                continue;
            }
            fsCourseTrafficLogMapper.insertCourseTrafficLogByTwoDaysLaterBatch(redPacketLogs);
            Long[] delArray = redPacketLogs.stream()
                    .map(FsCourseTrafficLog::getLogId)
                    .toArray(Long[]::new);
            fsCourseTrafficLogMapper.deleteFsCourseTrafficLogByLogIds(delArray);

            // 打印进度
            log.info("已处理: {}/{} ({:.2f}%)",
                    Math.min(offset + limit, count),
                    count,
                    (double)(offset + limit) / count * 100);

            // Calculate estimated remaining time
            long currentTime = System.currentTimeMillis();
            long elapsedTime = currentTime - startTime;
            double timePerBatch = (double)elapsedTime / (page + 1);
            long estimatedRemaining = (long)(timePerBatch * (totalPages - page - 1));

            log.info("当前批次耗时: {:.2f}s, 预计剩余时间: {}",
                    timePerBatch / 1000,
                    formatDuration(estimatedRemaining));
        }

        // End timing
        long endTime = System.currentTimeMillis();
        log.info("处理完成，时间: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        log.info("总耗时: {}", formatDuration(endTime - startTime));
    }

    @Override
    public List<FsCourseTrafficLogListVO> selectTrafficNew(FsCourseTrafficLogParam param) {
        if(StringUtils.isBlank(param.getStartDate()) && StringUtils.isBlank(param.getEndDate())){
            throw new CustomException("搜索必须要一个时间范围!");
        }
        if (ObjectUtils.isNotEmpty(param.getTabType())&&param.getTabType().equals("common")){
            param.setCommon(param.getTabType());
        }
        List<FsCourseTrafficLogListVO> fsCourseTrafficLogListVOS = fsCourseTrafficLogMapper.selectTrafficNew(param);
        for (FsCourseTrafficLogListVO log : fsCourseTrafficLogListVOS) {
            if (ObjectUtils.isNotNull(log.getProject())) {
                String sysCourseProject = DictUtils.getDictLabel("sys_course_project", String.valueOf(log.getProject()));
                if (StringUtils.isNotBlank(sysCourseProject)) {
                    log.setProjectName(sysCourseProject);
                }
            }

            if (ObjectUtils.isNotNull(log.getCompanyId())) {
                String companyName = companyCacheService.selectCompanyNameById(log.getCompanyId());
                if (StringUtils.isNotBlank(companyName)) {
                    log.setCompanyName(companyName);
                }
            }

            if (ObjectUtils.isNotNull(log.getCourseId())) {
                String courseName = fsUserCourseCacheService.selectCourseNameByCourseId(log.getCourseId());
                if (StringUtils.isNotBlank(courseName)) {
                    log.setCourseName(courseName);
                }
            }
        }
        return fsCourseTrafficLogListVOS;
    }

    @Override
    public void updateTrafficStatus(InternetTrafficParam internetTrafficParam) {
        System.out.println("开始处理流量充值...");

        // 计算充值对应的流量
        double account = Double.parseDouble(internetTrafficParam.getAccount());

        SysConfig config = iSysConfigService.selectConfigByConfigKey("statis.config");
        JSONObject jsonObject = JSONObject.parseObject(config.getConfigValue());
        float trafficPrice = jsonObject.getFloatValue("trafficPrice");

        double trafficGB = account / trafficPrice;
        long trafficKB = (long) (trafficGB * 1024 * 1024);
        long trafficB = trafficKB * 1024;

        System.out.println("充值金额：" + account + " 元，对应可用流量：" + trafficKB + " KB (" + trafficB + " B)");

        long updatedTrafficKB = 0L;
        int pageSize = 1000;
        int pageNum = 0;
        int loopCount = 0;
        int maxLoop = 20;

        List<Long> idsToUpdate = new ArrayList<>();
        Set<Long> processedIds = new HashSet<>();
        long remainingTrafficKB = trafficKB;
        long totalInternetTrafficRemaining = 0L;

        while (updatedTrafficKB < trafficKB && loopCount < maxLoop) {
            loopCount++;
            int offset = pageNum * pageSize;

            List<TrafficRecord> trafficRecords =
                    fsCourseTrafficLogMapper.findUnusedRecordsWithTraffic(
                            internetTrafficParam.getCompanyId(), offset, pageSize);

            if (trafficRecords.isEmpty()) {
                break;
            }
            for (TrafficRecord record : trafficRecords) {
                Long logId = record.getLogId();

                if (processedIds.contains(logId)) {
                    continue;
                }
                if (updatedTrafficKB < trafficKB) {
                    updatedTrafficKB += record.getInternetTraffic();
                    idsToUpdate.add(logId);
                    remainingTrafficKB = Math.max(0, trafficKB - updatedTrafficKB);
                }

                processedIds.add(logId);
                totalInternetTrafficRemaining += record.getInternetTraffic();
            }

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }

            pageNum++;
        }

        List<Long> allUnprocessedIds = new ArrayList<>();
        pageNum = 0;
        boolean hasMore = true;

        while (hasMore && loopCount < maxLoop * 2) {
            loopCount++;
            int offset = pageNum * pageSize;

            List<TrafficRecord> allRecords =
                    fsCourseTrafficLogMapper.findUnusedRecordsWithTraffic(
                            internetTrafficParam.getCompanyId(), offset, pageSize);

            if (allRecords.isEmpty()) {
                hasMore = false;
                continue;
            }

            for (TrafficRecord record : allRecords) {
                Long logId = record.getLogId();
                if (!idsToUpdate.contains(logId)) {
                    allUnprocessedIds.add(logId);
                }
            }

            pageNum++;
        }
        if (!idsToUpdate.isEmpty()) {
            fsCourseTrafficLogMapper.updateStatusByIds(idsToUpdate, 1);
            System.out.println("共更新状态为1的记录数：" + idsToUpdate.size());
        }
        if (!allUnprocessedIds.isEmpty()) {
            fsCourseTrafficLogMapper.updateStatusByIds(allUnprocessedIds, 3);
            System.out.println("共更新状态为3的记录数：" + allUnprocessedIds.size());
        }

        Long count = fsCourseTrafficLogMapper.findRecordsNum(internetTrafficParam.getCompanyId());
        long overflowTrafficKB = Math.max(0, updatedTrafficKB - trafficKB) + count;
        if (overflowTrafficKB > 0) {
            System.out.println("已使用流量超过充值流量，超出部分：" + overflowTrafficKB + " KB");
        }

        System.out.println("充值总流量：" + trafficKB + " KB");
        System.out.println("已使用流量：" + updatedTrafficKB + " KB");


        // 系统配置更新逻辑 - 使用字节为单位
        SysConfig sysConfig = iSysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");

        // 计算溢出流量（字节）
        long overflowTrafficB = updatedTrafficKB * 1024;

        Long sum = Long.parseLong(sysConfig.getConfigValue()) + overflowTrafficB;
        String trafficCount = sum+"";

        if (ObjectUtils.isEmpty(sysConfig)) {
            sysConfig = new SysConfig();
            sysConfig.setConfigKey("redPacket.Traffic.config");
            sysConfig.setConfigName("红包流量配置");
            sysConfig.setConfigValue(trafficCount);
            iSysConfigService.insertConfig(sysConfig);
        } else {
            sysConfig.setConfigValue(trafficCount);
            iSysConfigService.updateConfig(sysConfig);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sumTrafficlog() {
        // 初始化参数
        int batchSize = 10000;
        Long lastId = 0L;
        long totalTraffic = 0L;
        Date currentDate = DateUtils.addHours(new Date(),-3);
        SysConfig sysConfig = iSysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");

        // 分批处理
        while (true) {
            // 分页查询ID
            List<Long> ids = fsCourseTrafficLogMapper.findRecordsByIdsPaged(
                    currentDate, lastId, batchSize);
            System.out.println(ids);

            if (CollectionUtils.isEmpty(ids)) {
                break;
            }
            // 统计本批次流量
            Long batchTraffic = fsCourseTrafficLogMapper.sumTrafficByIds(ids);
            // 批量更新状态
            int updatedCount = fsCourseTrafficLogMapper.updateStatusByIds(ids, 2);

            totalTraffic += batchTraffic;

        }
        log.info("数据跑完了，数据有：{}",totalTraffic);
        if (totalTraffic > 0) {
            updateConfig(sysConfig, totalTraffic);
        }
    }
    private void updateConfig(SysConfig sysConfig, long trafficSum) {
        try {
            if (sysConfig == null) {
                sysConfig = new SysConfig();
                sysConfig.setConfigKey("redPacket.Traffic.config");
                sysConfig.setConfigName("红包流量配置");
                sysConfig.setConfigValue("-" + trafficSum);
                iSysConfigService.insertConfig(sysConfig);
            } else {
                long newValue = Long.parseLong(sysConfig.getConfigValue()) - trafficSum;
                sysConfig.setConfigValue(String.valueOf(newValue));
                iSysConfigService.updateConfig(sysConfig);
            }
        } catch (NumberFormatException e) {
            throw new RuntimeException("配置值格式错误", e);
        }
    }
    private static String formatDuration(long millis) {
        long seconds = millis / 1000;
        long minutes = seconds / 60;
        long hours = minutes / 60;

        return String.format("%02d:%02d:%02d",
                hours,
                minutes % 60,
                seconds % 60);
    }

    /**
     * 流量统计汇总
     * @param param
     * @return
     */
    public List<StatisticsSummaryVO> getStatisticsSummaryList(StatisticsSummaryParam param){

        if(StringUtils.isBlank(param.getStartDate()) && StringUtils.isBlank(param.getEndDate())){
            throw new CustomException("搜索必须要一个时间范围!");
        }
        param.setEndDateQueryValue(addOneDay(param.getEndDate()));
        if(null == param.getStatisticsType()){
            throw new CustomException("请选择统计类型");
        }
        Map<Long,DeptFullPathVO> deptMp = new HashMap<>();
        boolean byDept = param.getStatisticsType().equals(2);
        //按照部门方式汇总
        if(byDept){
            if(null == param.getCompanyId()){
                throw new CustomException("请选择公司");
            }
            List<DeptFullPathVO> deptInfoList = companyDeptMapper.getDeptFullPathList(param.getCompanyId());
            deptMp = deptInfoList.stream().collect(Collectors.toMap(DeptFullPathVO::getDeptId, item -> item));
            if(CollectionUtils.isEmpty(deptInfoList)){
                throw new CustomException("该公司下没有部门");
            }
        }
        functionStartPage();
        List<StatisticsSummaryVO> res =  fsCourseTrafficLogMapper.getStatisticsSummaryList(param);
        //获取配置流量比例
        SysConfig config = iSysConfigService.selectConfigByConfigKey("statis.config");
        JSONObject jsonObject = JSONObject.parseObject(config.getConfigValue());
        float trafficPrice = jsonObject.getFloatValue("trafficPrice");

        for (StatisticsSummaryVO item : res) {
            item.formatTraffic();
            item.calculateAmount(new BigDecimal(trafficPrice));
            if(byDept){
                item.setDeptName(deptMp.get(item.getDeptId()).getFullPath());
            }
        }
        return res;
    }
    public static String addOneDay(String dateStr) {
        // 将字符串解析为LocalDate对象
        LocalDate date = LocalDate.parse(dateStr);

        // 加一天
        LocalDate newDate = date.plusDays(1);

        // 转换回字符串
        return newDate.toString();
    }
    protected void functionStartPage()
    {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        if (com.fs.common.utils.StringUtils.isNotNull(pageNum) && com.fs.common.utils.StringUtils.isNotNull(pageSize))
        {
            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
            Boolean reasonable = pageDomain.getReasonable();
            PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
        }
    }

    public List<StatisticsSummaryVO> getStatisticsSummaryListNotPage(StatisticsSummaryParam param){
        if(StringUtils.isBlank(param.getStartDate()) && StringUtils.isBlank(param.getEndDate())){
            throw new CustomException("必须要一个时间范围!");
        }
        param.setEndDateQueryValue(addOneDay(param.getEndDate()));
        if(null == param.getStatisticsType()){
            throw new CustomException("请选择统计类型");
        }
        Map<Long,DeptFullPathVO> deptMp = new HashMap<>();
        boolean byDept = param.getStatisticsType().equals(2);
        //按照部门方式汇总
        if(byDept){
            if(null == param.getCompanyId()){
                throw new CustomException("请选择公司");
            }
            List<DeptFullPathVO> deptInfoList = companyDeptMapper.getDeptFullPathList(param.getCompanyId());
            deptMp = deptInfoList.stream().collect(Collectors.toMap(DeptFullPathVO::getDeptId, item -> item));
            if(CollectionUtils.isEmpty(deptInfoList)){
                throw new CustomException("该公司下没有部门");
            }
        }

        List<StatisticsSummaryVO> res =  fsCourseTrafficLogMapper.getStatisticsSummaryList(param);
        //获取配置流量比例
        SysConfig config = iSysConfigService.selectConfigByConfigKey("statis.config");
        JSONObject jsonObject = JSONObject.parseObject(config.getConfigValue());
        float trafficPrice = jsonObject.getFloatValue("trafficPrice");

        for (StatisticsSummaryVO item : res) {
            item.formatTraffic();
            item.calculateAmount(new BigDecimal(trafficPrice));
            if(byDept){
                item.setDeptName(deptMp.get(item.getDeptId()).getFullPath());
            }
        }
        return res;
    }
}
