
package com.tmerclub.cloud.flow.util;

import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.api.product.dto.ProdEffectDTO;
import com.tmerclub.cloud.api.user.dto.MemberReqDTO;
import com.tmerclub.cloud.flow.constant.FlowDateTypeEnum;
import com.tmerclub.cloud.flow.dto.FlowAnalysisDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.Date;
import java.util.Objects;

/**
 * 流量统计计算工具类
 *
 * @author YXF
 */
public class FlowUtil {

    private static final Logger LOG = LoggerFactory.getLogger(FlowUtil.class);

    private static final int DEFAULT_ID_LENGTH = 18;
    /** 长度为8  **/
    private static final int EIGHT_IN_LENGTH = 8;

    private static final String ONE_CHARACTERS = "0";

    private static final String TWO_CHARACTERS = "00";

    private static final String THREE_CHARACTERS = "000";

    private static final String FOUR_CHARACTERS = "0000";

    private static final String FIVE_CHARACTERS = "00000";

    private static final String SIX_CHARACTERS = "000000";
    private static final String SEVEN_CHARACTERS = "0000000";
    private static final String EIGHT_CHARACTERS = "00000000";
    private static final String NINE_CHARACTERS = "000000000";
    private static final String TEN_CHARACTERS = "0000000000";
    private static final String ELEVEN_CHARACTERS = "00000000000";
    private static final String TWELVE_CHARACTERS = "000000000000";
    private static final String THIRTEEN_CHARACTERS = "0000000000000";

    public static Long getId(String id, int index) {
        return getId(id, index, DEFAULT_ID_LENGTH);
    }
    public static Long getId(String id, long index) {
        return getId(id, index, DEFAULT_ID_LENGTH);
    }

    public static Long getId(String id, int index, int idLength) {
        String indexStr = String.valueOf(index);
        int length = idLength - id.length() - indexStr.length();
        id = id + splicingId(length) + indexStr;
        return Long.parseLong(id);
    }

    public static Long getId(String id, long index, int idLength) {
        String indexStr = String.valueOf(index);
        int length = idLength - id.length() - indexStr.length();
        LOG.info("id:{}, index:{}, idLength:{}", id , index, idLength);
        id = id + splicingId(length) + indexStr;
        return Long.parseLong(id);
    }

    private static String splicingId(int length) {
        String idStr;
        switch (length) {
            case 1:
                idStr = ONE_CHARACTERS;
                break;
            case 2:
                idStr = TWO_CHARACTERS;
                break;
            case 3:
                idStr = THREE_CHARACTERS;
                break;
            case 4:
                idStr = FOUR_CHARACTERS;
                break;
            case 5:
                idStr = FIVE_CHARACTERS;
                break;
            case 6:
                idStr = SIX_CHARACTERS;
                break;
            case 7:
                idStr = SEVEN_CHARACTERS;
                break;
            case 8:
                idStr = EIGHT_CHARACTERS;
                break;
            case 9:
                idStr = NINE_CHARACTERS;
                break;
            case 10:
                idStr = TEN_CHARACTERS;
                break;
            case 11:
                idStr = ELEVEN_CHARACTERS;
                break;
            case 12:
                idStr = TWELVE_CHARACTERS;
                break;
            case 13:
                idStr = THIRTEEN_CHARACTERS;
                break;
            default:
                idStr = "";
                break;
        }
        return idStr;
    }

    public static Long timeToId(Date date) {
        String format = dateToString(date);
        return Long.parseLong(format + TWELVE_CHARACTERS);
    }

    public static Long timeToId(Date date, int idLength) {
        String format = dateToString(date);
        return Long.parseLong(format + splicingId(idLength - format.length()));
    }

    public static Long timeToId(Date date, Object o, int idLength) {
        String format = dateToString(date) + o.toString();
        return Long.parseLong(format + splicingId(idLength - format.length()));
    }

    public static Long stringToId(String str, int idLength) {
        return Long.parseLong(str + splicingId(idLength - str.length()));
    }

    public static void handleTime(FlowAnalysisDTO flowAnalysisDTO) {
        Date[] dateArray = getDateByDateType(flowAnalysisDTO.getStartTime(), flowAnalysisDTO.getDateType());
        flowAnalysisDTO.setStartTime(dateArray[0]);
        flowAnalysisDTO.setEndTime(dateArray[1]);
    }

    public static void handleTime(MemberReqDTO memberReqDTO) {
        Date[] dateArray = getDateByDateType(memberReqDTO.getStartTime(), memberReqDTO.getDateType());
        memberReqDTO.setStartTime(dateArray[0]);
        memberReqDTO.setEndTime(dateArray[1]);
    }

    public static void handleTime(ProdEffectDTO prodEffectDTO) {
        Date[] dateArray = getDateByDateType(prodEffectDTO.getStartTime(), prodEffectDTO.getDateType());
        prodEffectDTO.setStartTime(dateArray[0]);
        prodEffectDTO.setEndTime(dateArray[1]);
    }

    private static Date[] getDateByDateType(Date startTime, Integer dateType) {
        FlowDateTypeEnum flowDateTypeEnum = FlowDateTypeEnum.instance(dateType);
        Date endTime;
        if (Objects.equals(flowDateTypeEnum, FlowDateTypeEnum.WEEK)) {
            startTime = DateUtil.beginOfWeek(startTime);
            endTime = DateUtil.beginOfWeek(DateUtil.offsetWeek(startTime, flowDateTypeEnum.getNum()));
        } else if (Objects.equals(flowDateTypeEnum, FlowDateTypeEnum.MONTH)) {
            startTime = DateUtil.beginOfMonth(startTime);
            endTime = DateUtil.beginOfMonth(DateUtil.offsetMonth(startTime, flowDateTypeEnum.getNum()));
        } else if (FlowDateTypeEnum.nearlyTime(dateType)) {
            endTime = DateUtil.beginOfDay(new Date());
            startTime = DateUtil.offsetDay(endTime, -flowDateTypeEnum.getNum());
        } else if (Objects.equals(FlowDateTypeEnum.REAL_TIME.value(), dateType)) {
            // 今日实时为当天的时间
            startTime = DateUtil.beginOfDay(new Date());
            endTime = DateUtil.offsetDay(startTime, 1);
        } else {
            startTime = DateUtil.beginOfDay(startTime);
            endTime = DateUtil.offsetDay(startTime, flowDateTypeEnum.getNum());
        }
        return new Date[]{startTime, endTime};
    }

    public static Integer getFlowSystemId(Date startTime, Integer dateTime, Integer systemType) {
        String format = dateToString(startTime);
        int id = Integer.parseInt(format + dateTime + systemType);
        LOG.info("getFlowSystemId-id:{}", id);
        return id;
    }

    public static String dateToString(Date date) {
        String format = DateUtil.format(date, "yyMMdd");
        return format;
    }

    public static Date previousTime(Date startTime, Integer dateType) {
        if (Objects.isNull(startTime) || Objects.isNull(dateType)) {
            return null;
        }

        FlowDateTypeEnum flowDateTypeEnum = FlowDateTypeEnum.instance(dateType);

        Date date;
        if (Objects.equals(FlowDateTypeEnum.WEEK, flowDateTypeEnum)) {
            date = DateUtil.beginOfWeek(DateUtil.offsetWeek(startTime, -flowDateTypeEnum.getNum()));
        } else if (Objects.equals(FlowDateTypeEnum.MONTH.value(), flowDateTypeEnum)) {
            date = DateUtil.beginOfMonth(DateUtil.offsetMonth(startTime, -flowDateTypeEnum.getNum()));
        } else {
            date = DateUtil.offsetDay(startTime, -flowDateTypeEnum.getNum());
        }
        return date;
    }

    public static Date previousTime(Date startTime, Integer dateType, Integer offset) {
        if (Objects.isNull(startTime) || Objects.isNull(dateType)) {
            return null;
        }

        Date date;
        if (Objects.equals(FlowDateTypeEnum.WEEK.value(), dateType)) {
            date = DateUtil.beginOfWeek(DateUtil.offsetWeek(startTime, -offset));
        } else if (Objects.equals(FlowDateTypeEnum.MONTH.value(), dateType)) {
            date = DateUtil.beginOfMonth(DateUtil.offsetMonth(startTime, -offset));
        } else {
            date = DateUtil.offsetDay(startTime, -offset);
        }
        return date;
    }

    public static String formatOnDateType(Date date, Integer dateType) {
        String format;
        if (Objects.equals(FlowDateTypeEnum.MONTH.value(), dateType)) {
            format = DateUtil.format(date, "yyyy-MM") ;
        } else if (Objects.equals(FlowDateTypeEnum.WEEK.value(), dateType)) {
            int week = DateUtil.weekOfYear(date);
            format = DateUtil.format(date, "yyyy") + "第" + week + "周";
        } else {
            format = DateUtil.format(date, "yyyy-MM-dd");
        }
        return format;
    }

    public static Date increaseByDateType(Date currentTime, Integer dateType) {

        if (Objects.equals(FlowDateTypeEnum.MONTH, dateType)) {
            return DateUtil.beginOfMonth(DateUtil.offsetMonth(currentTime, 1));
        } else if (Objects.equals(FlowDateTypeEnum.WEEK, dateType)) {
            return DateUtil.beginOfWeek(DateUtil.offsetWeek(currentTime, 1));
        }
        return DateUtil.offsetDay(currentTime, 1);
    }

    public static Query getRemoveQuery(Date beginDate, Date endDate, int idLength, Integer dateType) {
        // 近期数据的删除--由于只保存一份最新的统计数据，且每天都在更新日期不固定，所以通过时间类型来删除
        if (FlowDateTypeEnum.nearlyTime(dateType)) {
            return new Query(Criteria.where("dateType").is(dateType)) ;
        }

        Long beginId = FlowUtil.timeToId(beginDate, idLength);
        Long endId = FlowUtil.timeToId(endDate, idLength);
        // 先删除再更新-mongo没有事务，如果之前保存后程序报错了，数据还是保存在mongodb中
        return new Query(Criteria.where("_id").gte(beginId).lt(endId).and("dateType").is(dateType));
    }
}
