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

import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.enums.PlatformChannelEnum;
import com.red.circle.common.business.enums.SendPropsOrigin;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.dto.cmd.PropCouponUseCmd;
import com.red.circle.other.domain.gateway.PropCouponGateway;
import com.red.circle.other.domain.propcoupon.PropCoupon;
import com.red.circle.other.domain.propcoupon.PropCouponStatus;
import com.red.circle.other.domain.propcoupon.PropCouponType;
import com.red.circle.other.infra.database.rds.dao.props.PropCouponUseRecordDAO;
import com.red.circle.other.infra.database.rds.entity.props.PropCouponUseRecordDO;
import com.red.circle.other.infra.database.rds.entity.props.PropsCommodityStore;
import com.red.circle.other.infra.database.rds.service.props.PropsCommodityStoreService;
import com.red.circle.other.inner.asserts.OtherErrorCode;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.endpoint.live.RoomManagerClient;
import com.red.circle.other.inner.endpoint.material.props.*;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.enums.material.BadgeBackpackExpireTypeEnum;
import com.red.circle.other.inner.enums.material.ConsolePropsTypeEnum;
import com.red.circle.other.inner.enums.material.SysNobleVipTypeEnum;
import com.red.circle.other.inner.enums.sys.SysBadgeConfigTypeEnum;
import com.red.circle.other.inner.model.cmd.material.GiveBadgeCmd;
import com.red.circle.other.inner.model.cmd.material.GivePropsBackpackCmd;
import com.red.circle.other.inner.model.dto.material.PropsCommodityStoreDTO;
import com.red.circle.other.inner.model.dto.material.props.PropsNobleVipAbilityDTO;
import com.red.circle.tool.core.parse.DataTypeUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 使用道具券执行器
 *
 * @author system
 * @date 2025-11-05
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PropCouponUseCmdExe {

    private final PropCouponGateway propCouponGateway;
    private final PropsBackpackClient propsBackpackClient;
    private final BadgeBackpackClient badgeBackpackClient;
    private final RoomThemeBackpackClient roomThemeBackpackClient;
    private final PropCouponUseRecordDAO propCouponUseRecordDAO;
    private final PropsCommodityStoreClient propsCommodityStoreClient;
    private final UserProfileClient userProfileClient;
    private final PropsNobleVipClient propsNobleVipClient;
    private final RoomManagerClient roomManagerClient;

    /**
     * 执行使用道具券
     */
    @Transactional(rollbackFor = Exception.class)
    public void execute(PropCouponUseCmd cmd) {
        Long userId = cmd.requiredReqUserId();

        // 1. 根据券编号查询券信息（加锁）
        PropCoupon propCoupon = propCouponGateway.selectByCouponNo(cmd.getCouponNo());
        ResponseAssert.notNull(OtherErrorCode.PROP_COUPON_NOT_FOUND, propCoupon);

        // 2. 校验券是否有效
        validateCoupon(propCoupon, userId);

        // 3. 根据券类型调用对应的赠送道具接口
        givePropsToUser(propCoupon, userId);

        // 4. 更新券状态为已使用
        propCoupon.setStatus(PropCouponStatus.USED);
        propCoupon.setUseTime(LocalDateTime.now());
        propCoupon.setUpdateTime(LocalDateTime.now());
        propCouponGateway.update(propCoupon);

        // 5. 记录使用记录
        saveUseRecord(propCoupon, userId);

        log.info("用户使用道具券成功, userId:{}, couponNo:{}, couponType:{}, propId:{}",
                userId, cmd.getCouponNo(), propCoupon.getCouponType().getDesc(), propCoupon.getPropId());
    }

    /**
     * 校验券是否有效
     */
    private void validateCoupon(PropCoupon propCoupon, Long userId) {
        // 校验券是否属于当前用户
        ResponseAssert.isTrue(OtherErrorCode.PROP_COUPON_NOT_BELONG_TO_USER,
                Objects.equals(propCoupon.getUserId(), userId));

        // 校验券状态是否为未使用
        ResponseAssert.isTrue(OtherErrorCode.PROP_COUPON_ALREADY_USED,
                Objects.equals(propCoupon.getStatus(), PropCouponStatus.UNUSED));

        // 校验券是否已过期
        ResponseAssert.isTrue(OtherErrorCode.PROP_COUPON_EXPIRED,
                propCoupon.getExpireTime().isAfter(LocalDateTime.now()));
    }

    /**
     * 根据券类型赠送对应道具
     */
    private void givePropsToUser(PropCoupon propCoupon, Long userId) {
        PropCouponType couponType = propCoupon.getCouponType();
        Long propId = propCoupon.getPropId();
        Integer validDays = propCoupon.getPropDays();

        switch (couponType) {
            case AVATAR_FRAME:
                // 赠送头像框
                giveProps(userId, propId, ConsolePropsTypeEnum.AVATAR_FRAME.getName(), validDays);
                break;

            case RIDE:
                // 赠送座驾
                giveProps(userId, propId, ConsolePropsTypeEnum.RIDE.getName(), validDays);
                break;

            case NOBLE_VIP:
                // 赠送VIP（贵族VIP）
                PropsNobleVipAbilityDTO vipAbility = getVipAbilityBySysOriginSourceId(propId, SysOriginPlatformEnum.LIKEI.name());
                giveProps(userId, propId, ConsolePropsTypeEnum.NOBLE_VIP.getName(), validDays);

                if (Objects.nonNull(vipAbility.getCarId()) && !Objects
                    .equals(vipAbility.getCarId(), 0L)) {
                  giveProps(userId, vipAbility.getCarId(), ConsolePropsTypeEnum.RIDE.getName(), validDays);
                }

                if (Objects.nonNull(vipAbility.getAvatarFrameId())
                    && !Objects.equals(vipAbility.getAvatarFrameId(), 0L)) {
                  giveProps(userId, vipAbility.getAvatarFrameId(), ConsolePropsTypeEnum.AVATAR_FRAME.getName(), validDays);
                }

                if (Objects.nonNull(vipAbility.getChatBubbleId())
                    && !Objects.equals(vipAbility.getChatBubbleId(), 0L)) {
                  giveProps(userId, vipAbility.getChatBubbleId(), ConsolePropsTypeEnum.CHAT_BUBBLE.getName(), validDays);
                }

                if (Objects.nonNull(vipAbility.getDataCardId())
                    && !Objects.equals(vipAbility.getDataCardId(), 0L)) {
                  giveProps(userId, vipAbility.getDataCardId(), ConsolePropsTypeEnum.DATA_CARD.getName(), validDays);
                }

                roomManagerClient.updateRoomSettingMemberCapacity(userId,
                    vipAbility.getRoomMaxMember(), vipAbility.getAdminNumber());

                // 使用最大等级的VIP
                useMaxNobleVip(userId);
                break;

            case CHAT_BUBBLE:
                // 赠送聊天气泡
                giveProps(userId, propId, ConsolePropsTypeEnum.CHAT_BUBBLE.getName(), validDays);
                break;

            case THEME:
                // 赠送主题
                giveTheme(userId, propId, validDays);
                break;

            case DATA_CARD:
                // 赠送资料卡
                giveProps(userId, propId, ConsolePropsTypeEnum.DATA_CARD.getName(), validDays);
                break;

            case FLOAT_PICTURE:
                // 赠送飘屏
                giveProps(userId, propId, ConsolePropsTypeEnum.FLOAT_PICTURE.getName(), validDays);
                break;

            case BADGE:
                // 赠送徽章
//                giveBadge(userId, propId, validDays);
                break;

            case SPECIAL_ID:
                // 赠送靓号（暂不支持）
                ResponseAssert.failure(OtherErrorCode.PROP_COUPON_TYPE_NOT_SUPPORT);
                break;

            default:
                ResponseAssert.failure(OtherErrorCode.PROP_COUPON_TYPE_NOT_SUPPORT);
        }
    }

    private void useMaxNobleVip(Long receiverId) {
      PropsNobleVipAbilityDTO abilityDTO = propsNobleVipClient.getUserMaxAbilityDTO(receiverId).getBody();
      if (Objects.isNull(abilityDTO)) {
        return;
      }
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getId());
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getAvatarFrameId());
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getDataCardId());
      propsBackpackClient.switchUseProps(receiverId, abilityDTO.getCarId());
      userProfileClient.removeCacheAll(receiverId);
    }

    /**
     * 赠送普通道具（头像框、座驾、VIP、聊天气泡、资料卡、飘屏）
     */
    private void giveProps(Long userId, Long propId, String propsType, Integer validDays) {
        GivePropsBackpackCmd giveCmd = new GivePropsBackpackCmd()
                .setAcceptUserId(userId)
                .setPropsId(propId)
                .setType(propsType)
                .setOrigin(SendPropsOrigin.COUPON_EXCHANGE.name())
                .setOriginDesc(SendPropsOrigin.COUPON_EXCHANGE.getDesc())
                .setDays(validDays)
                .setUseProps(Boolean.TRUE)
                .setAllowGive(Boolean.FALSE);

        ResponseAssert.requiredSuccess(propsBackpackClient.giveProps(giveCmd));

        // 发送通知
        propsBackpackClient.givePropsNotify(userId, propsType, validDays, propId);
    }

    /**
     * 赠送主题
     */
    private void giveTheme(Long userId, Long themeId, Integer validDays) {
        ResponseAssert.requiredSuccess(
                roomThemeBackpackClient.sendRoomTheme(
                        userId,
                        themeId,
                        validDays,
                        SendPropsOrigin.COUPON_EXCHANGE
                )
        );

        // 发送通知
        propsBackpackClient.givePropsNotify(userId, ConsolePropsTypeEnum.THEME.getName(), validDays, themeId);
    }

    /**
     * 赠送徽章
     */
    private void giveBadge(Long userId, Long badgeId, Integer validDays) {
        // 徽章赠送天数大于1000天则为永久赠送
        BadgeBackpackExpireTypeEnum expireType;
        if (validDays >= 1000) {
            expireType = BadgeBackpackExpireTypeEnum.PERMANENT;
        } else {
            expireType = BadgeBackpackExpireTypeEnum.TEMPORARY;
        }

        ResponseAssert.requiredSuccess(
                badgeBackpackClient.giveBadge(new GiveBadgeCmd()
                        .setAcceptUserId(userId)
                        .setBadgeId(badgeId)
                        .setExpireType(expireType)
                        .setDays(validDays)
                        .setBadgeType(SysBadgeConfigTypeEnum.ACTIVITY)
                )
        );

        // 发送通知
        propsBackpackClient.givePropsNotify(userId, SysBadgeConfigTypeEnum.ACTIVITY.name(), validDays, badgeId);
    }

    private PropsNobleVipAbilityDTO getVipAbilityBySysOriginSourceId(Long propId,
                                                                     String sysOrigin) {
      PropsCommodityStoreDTO commodityStore = ResponseAssert.requiredSuccess(
          propsCommodityStoreClient.getPropsCommodityStore(sysOrigin, propId));
      ResponseAssert.notNull(OtherErrorCode.PROP_COUPON_PROP_NOT_FOUND, commodityStore);
      PropsNobleVipAbilityDTO nobleVipAbility = ResponseAssert.requiredSuccess(
          propsNobleVipClient.getAbilityDTO(commodityStore.getSourceId()));
      ResponseAssert.notNull(OtherErrorCode.PROP_COUPON_PROP_NOT_FOUND, nobleVipAbility);
      return nobleVipAbility;
    }

    /**
     * 保存使用记录
     */
    private void saveUseRecord(PropCoupon propCoupon, Long userId) {
        PropCouponUseRecordDO recordDO = new PropCouponUseRecordDO();
        recordDO.setCouponNo(propCoupon.getCouponNo());
        recordDO.setUserId(userId);
        recordDO.setCouponType(propCoupon.getCouponType().getCode());
        recordDO.setPropId(propCoupon.getPropId());
        recordDO.setPropIcon(propCoupon.getPropIcon());
        recordDO.setPropName(propCoupon.getPropName());
        recordDO.setValidDays(propCoupon.getValidDays());
        recordDO.setPropDays(propCoupon.getPropDays());
        recordDO.setActionType(1); // 1-使用
        recordDO.setRemark("用户使用道具券");
        recordDO.setCreateTime(LocalDateTime.now());

        propCouponUseRecordDAO.insert(recordDO);
    }
}
