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

import com.google.common.collect.Maps;
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.dto.team.TeamSalaryPaymentDetails;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamPolicyManager;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamSalaryPayment;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamSalaryPaymentService;
import com.red.circle.other.inner.model.dto.agency.agency.TeamSalaryPaymentRemark;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
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/4/13
 */
@Service
@RequiredArgsConstructor
public class TeamSalaryPaymentServiceImpl implements TeamSalaryPaymentService {

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

  /**
   * 验证主记录是否存在.
   */
  private boolean existsPrimary(String id) {
    return mongoPrimaryService.exists("team_salary_payment",
        Filters.eq("_id", id));
  }

  @Override
  public PageResult<TeamSalaryPayment> listByCondition(String sysOrigin, Long userId,
      Integer dateNumber, Integer pageNumber, Integer pageSize) {

    Criteria criteria = Criteria.where("sysOrigin").is(sysOrigin);

    if (Objects.nonNull(userId)) {
      criteria.and("userId").is(userId);
    }

    if (Objects.nonNull(dateNumber)) {
      criteria.and("dateNumber").is(dateNumber);
    }

    return mongoPageHelper.query(new Query(criteria),
        TeamSalaryPayment.class, pageSize, pageNumber, Sort.Order.desc("createTime"));

  }

  @Override
  public TeamSalaryPayment createIfAbsent(Long userId, Integer yearMonth, String sysOrigin) {

    String id = getId(userId, yearMonth);

    if (existsPrimary(id)) {
      return mongoTemplate
          .findOne(Query.query(Criteria.where("id").is(id)), TeamSalaryPayment.class);
    }

    return mongoTemplate.save(new TeamSalaryPayment()
        .setId(id)
        .setSysOrigin(sysOrigin)
        .setUserId(userId)
        .setDateNumber(yearMonth)
        .setRemarks(List.of(new TeamSalaryPaymentRemark()
                .setCreateTime(TimestampUtils.now())
                .setRemark("创建实时支付记录")
            )
        )
        .setCreateTime(TimestampUtils.now())
        .setExpiredTime(TimestampUtils.nowPlusDays(150))
    );
  }

  @Override
  public void addRemark(String id, String desc) {

    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
        new Update().push("remarks", new TeamSalaryPaymentRemark()
                .setRemark(desc)
                .setCreateTime(TimestampUtils.now())
            )
            .set("updateTime", TimestampUtils.now()), TeamSalaryPayment.class);

  }

  @Override
  public void paymentSalary(String id, TeamSalaryPaymentDetails salaryDetails) {

    if (StringUtils.isBlank(id) || Objects.isNull(salaryDetails)) {
      return;
    }

    salaryDetails.setCreateTime(TimestampUtils.now());

    // 发送工资都默认设置为未收回
    salaryDetails.setRecycled(Boolean.FALSE);

    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
        new Update()
            .push("salarySendDetails", salaryDetails)
            .set("updateTime", TimestampUtils.now()),
        TeamSalaryPayment.class);

  }

  @Override
  public Boolean checkRepeatPayment(String id, Long memberId, String regionId, Integer policyLevel,
      String memberTargetId, Boolean checkMember) {

    // 根据主记录ID验证支付工资的子记录是否存在
    return mongoPrimaryService.exists("team_salary_payment",
        Filters.and(
            Filters.eq("_id", id),
            Filters.elemMatch("salarySendDetails", Filters.and(
                Filters.eq("teamMemberId", memberId),
                Filters.eq("teamRegionId", regionId),
                Filters.eq("policyLevel", policyLevel),
                Filters.eq("anchor", checkMember),
                Filters.eq("recycled", Boolean.FALSE),
                Filters.eq("memberTargetId", memberTargetId)
            ))));
  }

  @Override
  public Boolean checkRepeatPayment(String id, Long memberId, String regionId, Integer policyLevel,
      Boolean checkMember) {

    // 根据主记录ID验证支付工资的子记录是否存在
    return mongoPrimaryService.exists("team_salary_payment",
        Filters.and(
            Filters.eq("_id", id),
            Filters.elemMatch("salarySendDetails", Filters.and(
                Filters.eq("teamMemberId", memberId),
                Filters.eq("teamRegionId", regionId),
                Filters.eq("policyLevel", policyLevel),
                Filters.eq("anchor", checkMember),
                Filters.eq("recycled", Boolean.FALSE)
            ))));

  }

  @Override
  public Boolean checkRepeatAndBillIdPayment(String id, Long memberId, String regionId, Integer teamBillId, Integer policyLevel,
                                             String memberTargetId, Boolean checkMember) {

    // 根据主记录ID验证支付工资的子记录是否存在
    return mongoPrimaryService.exists("team_salary_payment",
            Filters.and(
                    Filters.eq("_id", id),
                    Filters.elemMatch("salarySendDetails", Filters.and(
                            Filters.eq("teamMemberId", memberId),
                            Filters.eq("teamRegionId", regionId),
                            Filters.eq("teamBillId", teamBillId),
                            Filters.eq("policyLevel", policyLevel),
                            Filters.eq("anchor", checkMember),
                            Filters.eq("recycled", Boolean.FALSE),
                            Filters.eq("memberTargetId", memberTargetId)
                    ))));
  }

  @Override
  public TeamSalaryPayment getOneById(String id) {

    return mongoTemplate.findOne(Query.query(Criteria.where("id").is(id)), TeamSalaryPayment.class);
  }

  @Override
  public void updateDetails(String id, List<TeamSalaryPaymentDetails> salarySendDetails) {

    if (Objects.isNull(id) || CollectionUtils.isEmpty(salarySendDetails)) {
      return;
    }

    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
        new Update()
            .set("salarySendDetails", salarySendDetails)
            .set("updateTime", TimestampUtils.now()),
        TeamSalaryPayment.class);

  }

  @Override
  public void updatePolicyMap(String id, Map<String, TeamPolicyManager> policyMap) {

    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(id)),
        new Update()
            .set("policyMap", policyMap)
            .set("updateTime", TimestampUtils.now()),
        TeamSalaryPayment.class);

  }

  @Override
  public Map<String, TeamPolicyManager> mapPolicy(String id) {

    TeamSalaryPayment salaryPayment = mongoTemplate
        .findOne(Query.query(Criteria.where("id").is(id)), TeamSalaryPayment.class);

    if (Objects.isNull(salaryPayment)) {
      return Maps.newHashMap();
    }

    return Optional.ofNullable(salaryPayment.getPolicyMap()).orElse(Maps.newHashMap());
  }

  private String getId(Long userId, Integer yearMonth) {
    return userId + "_" + yearMonth;
  }


}
