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

import com.red.circle.external.inner.endpoint.message.OfficialNoticeClient;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateTypeCmd;
import com.red.circle.external.inner.model.enums.message.OfficialNoticeTypeEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.user.relation.cp.loveletter.SendLoveLetterCmd;
import com.red.circle.other.app.util.OfficialNoticeUtils;
import com.red.circle.other.domain.gateway.user.CpLoveLetterGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.cp.CpLoveLetterDomain;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.inner.asserts.user.UserRelationErrorCode;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.tuple.PennyAmount;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.error.WalletErrorCode;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * 发送CP告白信封
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class SendLoveLetterCmdExe {

    private final CpLoveLetterGateway cpLoveLetterGateway;
    private final CpRelationshipService cpRelationshipService;
    private final WalletGoldClient walletGoldClient;
    private final OfficialNoticeClient officialNoticeClient;
    private final UserProfileGateway userProfileGateway;
    private final UserProfileAppConvertor userProfileAppConvertor;

    private static final Long LOVE_LETTER_COST = 5000L;

    @Transactional(rollbackFor = Exception.class)
    public void execute(SendLoveLetterCmd cmd) {
        Long senderId = cmd.requiredReqUserId();
        Long receiverId = cmd.getReceiverId();

        // 校验双方是否已建立CP关系
        boolean cpExists = cpRelationshipService.existsCp(senderId, receiverId);
        ResponseAssert.isTrue(UserRelationErrorCode.CP_RELATIONSHIP_NOT_EXISTS, cpExists);

        // 扣除金币
        deductGold(senderId, cmd);

        // 保存信封
        CpLoveLetterDomain letter = new CpLoveLetterDomain();
        letter.setSenderId(senderId);
        letter.setReceiverId(receiverId);
        letter.setContent(cmd.getContent());
        letter.setStatus(0);
        letter.setIsPublic(cmd.getIsPublic() != null ? cmd.getIsPublic() : 1);
        letter.setCostGold(LOVE_LETTER_COST);
        letter.setCreateTime(TimestampUtils.now());
        letter.setUpdateTime(TimestampUtils.now());
        cpLoveLetterGateway.save(letter);

        // 发送System消息通知
        sendNotification(senderId, receiverId, cmd.getContent(), letter.getId());
    }

    private void deductGold(Long userId, SendLoveLetterCmd cmd) {
        GoldReceiptCmd build = GoldReceiptCmd.builder()
                .appExpenditure()
                .userId(userId)
                .amount(PennyAmount.ofDollar(LOVE_LETTER_COST))
                .eventId(String.valueOf(userId))
                .sysOrigin(cmd.getReqSysOrigin().getOrigin())
                .origin(GoldOrigin.CP_LOVE_LETTER)
                .build();

        try {
            walletGoldClient.changeBalance(build);
        } catch (Exception e) {
            log.error("扣除金币失败 userId={} cost={}", userId, LOVE_LETTER_COST, e);
            ResponseAssert.isTrue(WalletErrorCode.INSUFFICIENT_BALANCE, false);
        }
    }

    private void sendNotification(Long senderId, Long receiverId, String content, Long letterId) {
        UserProfileDTO senderProfile = userProfileAppConvertor.toUserProfileDTO(
                userProfileGateway.getByUserId(senderId)
        );

        Map<Object, Object> templateParam = OfficialNoticeUtils.buildUserProfile(senderProfile);
        templateParam.put("content", content);
        officialNoticeClient.send(NoticeExtTemplateTypeCmd.builder()
                .toAccount(receiverId)
                .noticeType(OfficialNoticeTypeEnum.CP_LOVE_LETTER)
                .templateParam(templateParam)
                .expand(letterId)
                .build()
        );
    }
}
