package com.red.circle.other.infra.database.mongo.service.activity.impl;

import com.mongodb.client.model.Filters;
import com.red.circle.component.mongodb.config.MongoPrimaryService;
import com.red.circle.component.mongodb.page.MongoPageHelper;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.infra.database.mongo.entity.activity.AgentActivityCount;
import com.red.circle.other.infra.database.mongo.service.activity.AgentActivityCountService;
import com.red.circle.other.infra.utils.DateFormatEnum;
import com.red.circle.other.infra.utils.ZonedDateTimeUtils;
import com.red.circle.other.inner.enums.activity.AgentActivityCountType;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.text.StringUtils;

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

/**
 * 代理活动.
 *
 * @author pengshigang on 2023/5/25
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AgentActivityCountServiceImpl implements AgentActivityCountService {

  private final MongoTemplate mongoTemplate;
  private final MongoPageHelper mongoPageHelper;
  private final MongoPrimaryService mongoPrimaryService;

  @Override
  public void incrTarget(Long teamId, Long target, String regionId) {

    if (target <= 0 || Objects.isNull(teamId) || StringUtils.isBlank(regionId)) {
      return;
    }

    // 本周一时间
    Integer weekMonday = ZonedDateTimeAsiaRiyadhUtils.nowWeekMondayToInt();

    String weekId = getGenerateId(teamId, weekMonday, "WEEK");
    if (existsPrimaryUnpaid(weekId)) {

      mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(weekId)),
          new Update().inc("target", target), AgentActivityCount.class);

    } else {

      mongoTemplate.save(new AgentActivityCount()
          .setId(weekId)
          .setRegionId(regionId)
          .setTeamId(teamId)
          .setTarget(target)
          .setDateNumber(weekMonday)
          .setGroup("WEEK")
          .setHistory(Boolean.FALSE)
          .setHistoryTopUser(Boolean.FALSE)
          .setCreateTime(TimestampUtils.now())
          .setExpiredTime(TimestampUtils.nowPlusDays(60))
      );

    }

    // 获得本月一号时间
    Integer firstDayOfMonth = ZonedDateTimeAsiaRiyadhUtils.nowFirstDayOfMonthToInt();

    String monthId = getGenerateId(teamId, firstDayOfMonth, "MONTH");
    if (existsPrimaryUnpaid(monthId)) {

      mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(monthId)),
          new Update().inc("target", target), AgentActivityCount.class);

    } else {

      mongoTemplate.save(new AgentActivityCount()
          .setId(monthId)
          .setRegionId(regionId)
          .setTeamId(teamId)
          .setTarget(target)
          .setDateNumber(firstDayOfMonth)
          .setGroup("MONTH")
          .setHistory(Boolean.FALSE)
          .setHistoryTopUser(Boolean.FALSE)
          .setCreateTime(TimestampUtils.now())
          .setExpiredTime(TimestampUtils.nowPlusDays(150))
      );
    }

  }

  private String getGenerateId(Long teamId, Integer dateNumber, String group) {

    return teamId + "_" + group + "_" + dateNumber;

  }

  private boolean existsPrimaryUnpaid(String id) {

    return mongoPrimaryService.exists("agent_activity_count",
        Filters.eq("_id", id)
    );
  }

  @Override
  public void reduceTarget(Collection<Long> teamIds, Long target) {

    if (CollectionUtils.isEmpty(teamIds) || target <= 0) {
      return;
    }

    List<AgentActivityCount> countList = mongoTemplate.find(Query.query(Criteria
        .where("teamId").in(teamIds)
        .and("history").is(Boolean.FALSE)
        .and("target").gt(0L)), AgentActivityCount.class);
    if (CollectionUtils.isEmpty(countList)) {
      return;
    }

    countList.forEach(count ->
        mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(count.getId())),
            new Update().set("target", count.getTarget() > target ? count.getTarget() - target : 0),
            AgentActivityCount.class));

  }

  @Override
  public void removeByTeamIds(Collection<Long> teamIds) {

    mongoTemplate.remove(Query.query(Criteria.where("teamId").in(teamIds)
        .and("history").is(Boolean.FALSE)), AgentActivityCount.class);
  }

  @Override
  public void updateHistoryTopUserByIds(Set<String> ids) {

    if (CollectionUtils.isEmpty(ids)) {
      return;
    }

    mongoTemplate.updateMulti(Query.query(Criteria.where("id").in(ids)), new Update()
            .set("historyTopUser", Boolean.TRUE).set("history", Boolean.TRUE),
        AgentActivityCount.class);

  }


  @Override
  public List<AgentActivityCount> historyLimit33(String regionId, String group) {

    return mongoTemplate.find(Query.query(Criteria.where("regionId").is(regionId)
            .and("group").is(group)
            .and("history").is(Boolean.TRUE)
            .and("historyTopUser").is(Boolean.TRUE))
        .with(Sort.by(Sort.Order.desc("dateNumber"), Sort.Order.desc("target")))
        .limit(33), AgentActivityCount.class);
  }

  @Override
  public List<AgentActivityCount> listTop15(String regionId, String group) {

    return mongoTemplate.find(Query.query(Criteria.where("regionId").is(regionId)
            .and("group").is(group)
            .and("history").is(Boolean.FALSE))
        .with(Sort.by(Sort.Order.desc("target")))
        .limit(15), AgentActivityCount.class);

  }

  @Override
  public AgentActivityCount own(Long teamId, String group) {

    return mongoTemplate
        .findOne(Query.query(Criteria.where("teamId").is(teamId).and("history").is(Boolean.FALSE)
            .and("group").is(group)), AgentActivityCount.class);

  }

  @Override
  public void updateCancelUserTop(String id) {

    if (StringUtils.isBlank(id)) {
      return;
    }

    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
        new Update().set("historyTopUser", Boolean.FALSE), AgentActivityCount.class);

  }


  @Override
  public PageResult<AgentActivityCount> pageData(AgentActivityCountType group, String regionId,
      Integer pageNumber, Integer pageSize) {

//    Criteria criteria = Criteria.where("historyTopUser").is(Boolean.TRUE)
//        .and("history").is(Boolean.TRUE);

    Integer dateNumber = getPreviousMonday();
    Criteria criteria = Criteria.where("dateNumber").is(dateNumber);

    if (Objects.nonNull(group)) {
      criteria.and("group").is(group);
    }
    if (StringUtils.isNotBlank(regionId)) {
      criteria.and("regionId").is(regionId);
    }

    return mongoPageHelper
        .query(new Query(criteria), AgentActivityCount.class, pageSize,
            pageNumber, Sort.Order.desc("dateNumber"), Sort.Order.desc("target"));

  }

  private static int getPreviousMonday() {
    LocalDate today = LocalDate.now();
    LocalDate previousMonday = today.minusWeeks(1)
            .with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));

    return Integer.parseInt(previousMonday.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE));
  }


  @Override
  public List<AgentActivityCount> top10Team(String group, String regionId) {

    // 时间
    Integer dateNumber = ZonedDateTimeUtils.nowAsiaRiyadhFirstDayOfLastMonthToInt();
    if ("WEEK".equals(group)) {
      dateNumber = ZonedDateTimeUtils.getAsiaRiyadhLastWeekMondayToInt();
    }

    return mongoTemplate.find(Query.query(Criteria.where("regionId").is(regionId)
            .and("group").is(group)
            .and("dateNumber").is(dateNumber))
        .with(Sort.by(Sort.Order.desc("target")))
        .limit(10), AgentActivityCount.class);
  }


  @Override
  public void updateHistory(String group) {

    // 时间
    Integer dateNumber;
    String desc;
    if ("WEEK".equals(group)) {
      dateNumber = ZonedDateTimeUtils.getAsiaRiyadhLastWeekMondayToInt();
      desc = ZonedDateTimeUtils.getAsiaRiyadhLastWeekMondayToFormat(DateFormatEnum.yyyy_MM_dd) + "/"
          + ZonedDateTimeUtils.getAsiaRiyadhLastWeekSunday(DateFormatEnum.yyyy_MM_dd);
    } else {
      dateNumber = ZonedDateTimeUtils.nowAsiaRiyadhFirstDayOfLastMonthToInt();
      desc = ZonedDateTimeUtils.getAsiaRiyadhFirstDayOfMonthByLastMonth(DateFormatEnum.yyyy_MM_dd)
          + "/" + ZonedDateTimeUtils
          .getAsiaRiyadhLastDayOfMonthByLastMonth(DateFormatEnum.yyyy_MM_dd);
    }

    mongoTemplate.updateMulti(Query.query(Criteria.where("group").is(group)
        .and("dateNumber").is(dateNumber)), new Update()
        .set("history", Boolean.TRUE)
        .set("dateDesc", desc), AgentActivityCount.class);
  }
}
