package com.ycwl.basic.service.mobile.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.ycwl.basic.enums.StatisticEnum;
import com.ycwl.basic.mapper.StatisticsMapper;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
import com.ycwl.basic.model.mobile.statistic.resp.AppSta1VO;
import com.ycwl.basic.model.mobile.statistic.resp.AppSta2VO;
import com.ycwl.basic.model.mobile.statistic.resp.AppSta3VO;
import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
import com.ycwl.basic.service.mobile.AppStatisticsService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Map;

/**
 * @Author：longbinbin
 * @Date：2024/12/12 9:48
 */
@Service
public class AppStatisticsServiceImpl implements AppStatisticsService {

    @Autowired
    private StatisticsMapper statisticsMapper;


    /**
     * 支付订单金额、预览_支付转化率、扫码_付费用户转化率
     * @param query
     * @return
     */
    @Override
    public ApiResponse<AppSta1VO> oneStatistics(CommonQueryReq query) {
        AppSta1VO vo = new AppSta1VO();
        //订单金额格式
        DecimalFormat orderAmountDf = new DecimalFormat("0.0");
        //转化率格式
        DecimalFormat df = new DecimalFormat("0.00");
        if(query.getEndTime()==null && query.getStartTime()==null){
            // 没有传时间，则代表用户没有自定义查询时间，使用standard来判断查询时间范围
            Integer standard = query.getStandard();
            if(standard==null){
                query.setStandard(0);
            }
            //获取当前周期的具体时间范围
            standardToNewSpecificTime(query);
            //查询处理数据逻辑
            oneStatisticsHandler(1,query,vo);
            //----------------------------------------------------
            //获取上一个周期的具体时间范围
            standardToPreviousSpecificTime(query);
            //查询处理数据逻辑
            oneStatisticsHandler(2,query,vo);
        }else{
            //自定义时间查询，只有当前数据，没有往期对比数据
            //查询处理数据逻辑
            oneStatisticsHandler(1,query,vo);
        }
        return ApiResponse.success(vo);
    }

    @Override
    public ApiResponse<AppSta2VO> twoStatistics(CommonQueryReq query) {
        AppSta2VO vo = new AppSta2VO();
        if(query.getEndTime()==null && query.getStartTime()==null){
            // 没有传时间，则代表用户没有自定义查询时间，使用standard来判断查询时间范围
            Integer standard = query.getStandard();
            if(standard==null){
                query.setStandard(0);
            }
            //获取当前周期的具体时间范围
            standardToNewSpecificTime(query);
            //查询处理数据逻辑
            twoStatisticsHandler(1,query,vo);
            //----------------------------------------------------
            //获取当前周期的具体时间范围
            standardToPreviousSpecificTime(query);
            //查询处理数据逻辑
            twoStatisticsHandler(2,query,vo);
        }else{
            //自定义时间查询，只有当前数据，没有往期对比数据
            //查询处理数据逻辑
            twoStatisticsHandler(1,query,vo);
        }
        return ApiResponse.success(vo);
    }

    @Override
    public ApiResponse<AppSta3VO> freeStatistics(CommonQueryReq query) {
        AppSta3VO vo = new AppSta3VO();
        if(query.getEndTime()==null && query.getStartTime()==null){
            // 没有传时间，则代表用户没有自定义查询时间，使用standard来判断查询时间范围
            Integer standard = query.getStandard();
            if(standard==null){
                query.setStandard(0);
            }
            //获取当前周期的具体时间范围
            standardToNewSpecificTime(query);
            //查询处理数据逻辑
            freeStatisticsHandler(1,query,vo);
            //----------------------------------------------------
            //获取当前周期的具体时间范围
            standardToPreviousSpecificTime(query);
            //查询处理数据逻辑
            freeStatisticsHandler(2,query,vo);
        }else{
            //自定义时间查询，只有当前数据，没有往期对比数据
            //查询处理数据逻辑
            freeStatisticsHandler(1,query,vo);
        }
        return ApiResponse.success(vo);
    }

    @Override
    public ApiResponse<AppStatisticsFunnelVO> userConversionFunnel(CommonQueryReq query) {
        AppStatisticsFunnelVO vo = new AppStatisticsFunnelVO();
        if(query.getEndTime()==null && query.getStartTime()==null){
            // 没有传时间，则代表用户没有自定义查询时间，使用standard来判断查询时间范围
            Integer standard = query.getStandard();
            if(standard==null){
                query.setStandard(0);
            }
            //获取当前周期的具体时间范围
            standardToNewSpecificTime(query);
        }



        //镜头检测游客数
        Integer cameraShotOfMemberNum=statisticsMapper.countCameraShotOfMember(query);
        //扫码访问人数
        // 扫小程序码或景区码进入访问的用户数，包括授权用户（使用OpenID进行精准统计）和未授权用户(使用 UUID统计访问)。但当用户授权时，获取OpenID并与UUID关联，删除本地UUID，避免重复记录。
        Integer scanCodeVisitorOfMemberNum=statisticsMapper.countScanCodeOfMember(query);
        //上传头像（人脸）人数
        // 上传了人脸的用户数（包括本地临时ID和获取到OpenID的，同一设备微信获取到OpenID要覆盖掉之前生成的临时ID），上传多张人脸都只算一个人。
        Integer uploadFaceOfMemberNum=statisticsMapper.countUploadFaceOfMember(query);
        //推送订阅人数
        // 只要点了允许通知，哪怕只勾选1条订阅都算
        Integer pushOfMemberNum =statisticsMapper.countPushOfMember(query);
        //生成视频人数
        // 生成过Vlog视频的用户ID数，要注意屏蔽掉以前没有片段也能生成的情况
        Integer completeVideoOfMemberNum =statisticsMapper.countCompleteVideoOfMember(query);
        //预览视频人数
        // 购买前播放了5秒的视频条数。
        Integer previewVideoOfMemberNum =statisticsMapper.countPreviewVideoOfMember(query);
        if (previewVideoOfMemberNum==null){
            previewVideoOfMemberNum=0;
        }
        //点击购买人数
        // 点了立即购买按钮的用户ID就算，包括支付的和未支付的都算，只要点击了。
        Integer clickOnPayOfMemberNum =statisticsMapper.countClickPayOfMember(query);
        //支付订单人数
        Integer payOfMemberNum =statisticsMapper.countPayOfMember(query);
        //总访问人数
        // 通过任何途径访问到小程序的总人数，包括授权用户和未授权用户。
        Integer totalVisitorOfMemberNum =statisticsMapper.countTotalVisitorOfMember(query);
//        Integer totalVisitorOfMemberNum =scanCodeVisitorOfMemberNum;
        //生成视频条数
        // 仅指代生成的Vlog条数，不包含录像原片。
        Integer completeOfVideoNum =statisticsMapper.countCompleteOfVideo(query);
        //预览视频条数
        Integer previewOfVideoNum =statisticsMapper.countPreviewOfVideo(query);
        //支付订单数
        Integer payOfOrderNum =statisticsMapper.countPayOfOrder(query);
        //支付订单金额
        BigDecimal payOfOrderAmount =statisticsMapper.countOrderAmount(query);
        //退款订单数
        Integer refundOfOrderNum =statisticsMapper.countRefundOfOrder(query);
        //退款订单金额
        BigDecimal refundOfOrderAmount =statisticsMapper.countRefundAmount(query);

        vo.setScanCodeVisitorOfMemberNum(scanCodeVisitorOfMemberNum);
        vo.setUploadFaceOfMemberNum(uploadFaceOfMemberNum);
        vo.setPushOfMemberNum(pushOfMemberNum);
        vo.setCompleteVideoOfMemberNum(completeVideoOfMemberNum);
        vo.setPreviewVideoOfMemberNum(previewVideoOfMemberNum);
        vo.setClickOnPayOfMemberNum(clickOnPayOfMemberNum);
        vo.setPayOfMemberNum(payOfMemberNum);

        //转化率格式
        DecimalFormat df = new DecimalFormat("0.0");

        vo.setTotalVisitorOfMemberNum(totalVisitorOfMemberNum);
        vo.setCompleteOfVideoNum(completeOfVideoNum);
        vo.setPreviewOfVideoNum(previewOfVideoNum);
        vo.setPayOfOrderNum(payOfOrderNum);
        vo.setPayOfOrderAmount(payOfOrderAmount.setScale(2, RoundingMode.HALF_UP));
        vo.setRefundOfOrderNum(refundOfOrderNum);
        vo.setRefundOfOrderAmount(refundOfOrderAmount.setScale(2, RoundingMode.HALF_UP));

        return ApiResponse.success(vo);
    }

    @Override
    public ApiResponse<String> addStatistics(StatisticsRecordAddReq req) {
//        req.setId(SnowFlakeUtil.getLongId());
        if (req.getMemberId() == null) {
            try {
                JwtInfo worker = JwtTokenUtil.getWorker();
                Long userId = worker.getUserId();
                req.setMemberId(userId);
            } catch (Exception ignored) {

            }
        }
        Integer type = req.getType();
        if(type==null){
            return ApiResponse.fail("类型不能为空");
        }
        Map<Integer, StatisticEnum> valueMap = StatisticEnum.cacheMap;
        if(!valueMap.containsKey(type)){
            return ApiResponse.fail("添加失败，类型不存在");
        }
        int i=statisticsMapper.addStatisticsRecord(req);
        if(i==0){
            return ApiResponse.fail("添加失败");
        }else{
            return ApiResponse.success("添加成功");
        }
    }

    /**
     *
     * @param num1
     * @param num2
     * @return
     */
    private String calculateConversionRate(Integer num1,Integer num2){
        //转化率格式
        DecimalFormat df = new DecimalFormat("0.00");
        if(num2 == null || num2==0){
            return "0.00";
        }else {
            BigDecimal result = new BigDecimal(num1).divide(new BigDecimal(num2), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            return df.format(result);
        }
    }



    /**
     *
     * @param cycle 周期 1当前 2往期
     * @param query
     * @param vo
     */
    private void freeStatisticsHandler(Integer cycle,CommonQueryReq query,AppSta3VO vo){
        //查询扫码访问人数
        int sceneNum=statisticsMapper.countScanCodeOfMember(query);
        //查询推送订阅人数
        int pushNum=statisticsMapper.countPushOfMember(query);
        // 查询预览视频人数
        Integer previewNum=statisticsMapper.countPreviewVideoOfMember(query);

        if(cycle==1){
            //当前周期的扫码访问人数
            vo.setNowScanCodeOfPeopleNum(sceneNum);
            //当前周期的推送订阅人数
            vo.setNowPushOfPeopleNum(pushNum);
            //当前周期的预览视频人数
            vo.setNowPreviewVideoOfPeopleNum(previewNum);
        }else if(cycle==2){
            //上一个周期的扫码访问人数
            vo.setPreviousScanCodeOfPeopleNum(sceneNum);
            //上一个周期的推送订阅人数
            vo.setPreviousPushOfPeopleNum(pushNum);
            //上一个周期的预览视频人数
            vo.setPreviousPreviewVideoOfPeopleNum(previewNum);
        }
    }

    /**
     *
     * @param cycle 周期 1当前 2往期
     * @param query
     * @param vo
     */
    private void twoStatisticsHandler(Integer cycle,CommonQueryReq query,AppSta2VO vo){
        //查询现场支付订单数
        int sceneOrderNum=statisticsMapper.countSceneOrderNum(query);
        //查询推送支付订单数
        int pushOrderNum=statisticsMapper.countPushOrderNum(query);
        // 当前周期的总支付订单数
        Integer totalOrderNum=sceneOrderNum+pushOrderNum;

        if(cycle==1){
            //当前周期的总支付订单数
            vo.setNowPayOrderNum(totalOrderNum);
            //当前周期的现场支付订单数
            vo.setNowSceneOrderNum(sceneOrderNum);
            //当前周期的推送支付订单数
            vo.setNowPushOrderNum(pushOrderNum);
        }else if(cycle==2){
            //上一个周期的总支付订单数
            vo.setPreviousPayOrderNum(totalOrderNum);
            //上一个周期的现场支付订单数
            vo.setPreviousSceneOrderNum(sceneOrderNum);
            //上一个周期的推送支付订单数
            vo.setPreviousPushOrderNum(pushOrderNum);
        }
    }

    /**
     *
     * @param cycle 周期 1当前 2往期
     * @param query
     * @param vo
     */
    private void oneStatisticsHandler(Integer cycle,CommonQueryReq query,AppSta1VO vo){
        //订单金额格式
        DecimalFormat orderAmountDf = new DecimalFormat("0.0");
        //转化率格式
        DecimalFormat df = new DecimalFormat("0.00");
        // 计算当前周期的支付订单金额
        BigDecimal orderAmount=statisticsMapper.countOrderAmount(query).setScale(2, RoundingMode.HALF_UP);
        //查询预览视频人数
        int preview=statisticsMapper.countPreviewVideoOfMember(query);
        //查询扫码人数
        int scanCode=statisticsMapper.countScanCodeOfMember(query);
        //查询付费人数
        int pay=statisticsMapper.countPayOfMember(query);
        int payCount=statisticsMapper.countPayOfOrder(query);

        if(cycle==1){
            // 支付过订单的金额，包含已退款的金额。
            vo.setNowOrderAmount(orderAmountDf.format(orderAmount));
            // 订单数÷预览人数。假设一共5个人预览，产生了3个订单，其实是2个人支付的（其中1人购买2单），预览-支付转化率是3÷5，而不是2÷5。
            if(preview==0){
                vo.setNowPreviewPay("0.00");
            }else {
                BigDecimal previewPay = new BigDecimal(payCount).divide(new BigDecimal(preview), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                vo.setNowPreviewPay(df.format(previewPay));
            }
            // 付费的用户人数÷扫码的用户人数。此处是人数除以人数，而且是除以扫码人数，而不是预览人数。
            if(scanCode==0){
                vo.setNowScanCodePay("0.00");
            }else {
                BigDecimal scanCodePay = new BigDecimal(pay).divide(new BigDecimal(scanCode), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                vo.setNowScanCodePay(df.format(scanCodePay));
            }
        }else if(cycle==2){
            //上一个周期的支付订单金额
            // 支付过订单的金额，包含已退款的金额。
            vo.setPreviousOrderAmount(orderAmountDf.format(orderAmount));
            // 订单数÷预览人数。假设一共5个人预览，产生了3个订单，其实是2个人支付的（其中1人购买2单），预览-支付转化率是3÷5，而不是2÷5。
            if(preview==0){
                vo.setPreviousPreviewPay("0.00");
            }else {
                BigDecimal previewPay = new BigDecimal(payCount).divide(new BigDecimal(preview), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                vo.setPreviousPreviewPay(df.format(previewPay));
            }
            // 付费的用户人数÷扫码的用户人数。此处是人数除以人数，而且是除以扫码人数，而不是预览人数。
            if(scanCode==0){
                vo.setPreviousScanCodePay("0.00");
            }else {
                BigDecimal scanCodePay = new BigDecimal(pay).divide(new BigDecimal(scanCode), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                vo.setPreviousScanCodePay(df.format(scanCodePay));
            }
        }
    }





    /**
     * 根据standard来获取查询时间范围（当前周期）
     * @param query
     */
    private void standardToNewSpecificTime(CommonQueryReq query) {
        Integer standard = query.getStandard();
        Date newDate = DateUtil.beginOfDay(new Date());
        Date startDate = new Date();
        Date endDate = new Date();
        switch (standard) {
            case 4://年
                startDate = DateUtil.offset(newDate, DateField.YEAR, -1);
                break;
            case 3://月
                startDate = DateUtil.offset(newDate, DateField.MONTH, -1);
                break;
            case 2://周
                startDate = DateUtil.offsetWeek(newDate, -1);
                break;
            case 1://昨天
                startDate = DateUtil.offsetDay(newDate, -1);
                endDate = DateUtil.endOfDay(startDate);
                break;
            case 0://今天
                startDate = DateUtil.beginOfDay(newDate);
                break;
            case 9://历史累计
                startDate = null;
                endDate = null;
                break;
            default:
                break;
        }
        query.setStartTime(startDate);
        query.setEndTime(endDate);
    }

    /**
     * 根据standard来获取查询时间范围(上一个周期)
     * @param query
     */
    private void standardToPreviousSpecificTime(CommonQueryReq query) {
        Integer standard = query.getStandard();
        Date newDate = DateUtil.beginOfDay(new Date());
        Date startDate = new Date();
        Date endDate = new Date();
        switch (standard) {
            case 4://年，近一年的前一年
                startDate = DateUtil.offset(newDate, DateField.YEAR, -2);
                endDate = DateUtil.offset(newDate, DateField.YEAR, -1);
                break;
            case 3://月，近一月的前一个月
                startDate = DateUtil.offset(newDate, DateField.MONTH, -2);
                endDate = DateUtil.offset(newDate, DateField.MONTH, -1);
                break;
            case 2://周，近一周的前一周
                startDate = DateUtil.offsetWeek(newDate, -2);
                endDate = DateUtil.offsetWeek(newDate, -1);
                break;
            case 1://昨天，昨天的前一天
                startDate = DateUtil.offsetDay(newDate, -2);
                endDate = DateUtil.offsetDay(newDate, -1);
                break;
            case 0://今天，今天的前一天
                startDate = DateUtil.offsetDay(newDate, -1);
                endDate = DateUtil.endOfDay(startDate);
                break;
            case 9://历史累计
                startDate = null;
                endDate = null;
                break;
            default:
                break;
        }
        query.setStartTime(startDate);
        query.setEndTime(endDate);
    }
}
