package com.red.circle.other.app.command.team;

import com.alibaba.fastjson.JSON;
import com.red.circle.common.business.enums.OperationUserOrigin;
import com.red.circle.external.inner.endpoint.message.OfficialNoticeClient;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateCustomizeCmd;
import com.red.circle.external.inner.model.enums.message.OfficialNoticeTypeEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.team.TeamUserApplyCmd;
import com.red.circle.other.app.util.OfficialNoticeUtils;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.RegisterDeviceGateway;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamApplicationProcess;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamProfile;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamApplicationProcessService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.asserts.user.UserRelationErrorCode;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.model.dto.agency.agency.TeamStatus;
import com.red.circle.other.inner.enums.team.TeamAppProcessReason;
import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus;
import com.red.circle.other.inner.enums.team.TeamApplicationType;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 用户申请加入团队.
 *
 * @author pengshigang on 2022/12/20
 */
@Component
@RequiredArgsConstructor
public class TeamUserApplyJoinExe {

  private static final String TEAM_APPLY_NOTICE_TITLE = "apply agent";

  private final UserProfileGateway userProfileGateway;
  private final TeamMemberService teamMemberService;
  private final TeamProfileService teamProfileService;
  private final OfficialNoticeClient officialNoticeClient;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final TeamApplicationProcessService teamApplicationProcessService;
  private final RegisterDeviceGateway registerDeviceGateway;

  public String execute(TeamUserApplyCmd cmd) {

    UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
        userProfileGateway.getByUserId(cmd.getReqUserId()));
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, userProfile);

    ResponseAssert
        .isNull(TeamErrorCode.JOINED_TEAM, teamMemberService.getByMemberId(userProfile.getId()));

    TeamProfile teamProfile = teamProfileService.getById(cmd.getTeamId());
    ResponseAssert.notNull(TeamErrorCode.TEAM_NOT_FOUND, teamProfile);

    ResponseAssert.isTrue(TeamErrorCode.THE_TEAM_IS_FULL, teamProfile.checkAllowJoinTeam());

    ResponseAssert.isTrue(TeamErrorCode.TEAM_NOT_FOUND, Objects.equals(teamProfile.getStatus(),
        TeamStatus.AVAILABLE));

    ResponseAssert.isFalse(UserRelationErrorCode.EXIST_OR_REPEAT_APPLY_ERROR,
        teamApplicationProcessService.existWaitByUserId(userProfile.getId()));

    ResponseAssert.isFalse(TeamErrorCode.JOINED_TEAM,
        teamMemberService.existsMember(userProfile.getId()));

//    ResponseAssert.isFalse(TeamErrorCode.USER_IS_ALREADY_A_BD,
//        businessDevelopmentBaseInfoService.checkBD(userProfile.getId()));

    // 主播设备指纹校验
    Boolean hasAnchorWithSameDevice = registerDeviceGateway.checkDeviceFingerprintHasAnchor(
        cmd.getReqUserId());
    ResponseAssert.isFalse(TeamErrorCode.DEVICE_FINGERPRINT_USED_BY_ANCHOR, hasAnchorWithSameDevice);

    Long messageId = IdWorkerUtils.getId();
    teamApplicationProcessService.add(new TeamApplicationProcess()
        .setId(messageId)
        .setSysOrigin(teamProfile.getSysOrigin())
        .setType(TeamApplicationType.TEAM)
        .setReason(TeamAppProcessReason.JOIN)
        .setAssociateId(teamProfile.getId())
        .setStatus(TeamApplicationProcessStatus.WAIT)
        .setCreateTime(TimestampUtils.now())
        .setCreateUser(cmd.getReqUserId())
        .setCreateUserOrigin(OperationUserOrigin.APP.getValue())
        .setExpiredTime(TimestampUtils.nowPlusDays(60))
    );

    sendMessage(cmd, teamProfile, messageId);

    return Objects.toString(messageId);
  }

  private void sendMessage(TeamUserApplyCmd cmd, TeamProfile teamProfile, Long messageId) {
    UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
            userProfileGateway.getByUserId(cmd.requiredReqUserId())
    );
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);

    officialNoticeClient.send(NoticeExtTemplateCustomizeCmd.builder()
        .toAccount(teamProfile.getOwnUserId())
        .noticeType(OfficialNoticeTypeEnum.AGENT_SEND_INVITE_HOST)
        .title(TEAM_APPLY_NOTICE_TITLE)
        .content(JSON.toJSONString(OfficialNoticeUtils.buildUserProfile(userProfile)))
        .expand(Objects.toString(messageId))
        .build());
  }

}
