package com.ruoyi.cai.ws.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.ruoyi.cai.domain.Account;
import com.ruoyi.cai.dto.video.VideoSettleResp;
import com.ruoyi.cai.dto.video.WithholdingFeeUserResp;
import com.ruoyi.cai.manager.ConsumerManager;
import com.ruoyi.cai.manager.LockManager;
import com.ruoyi.cai.service.AccountService;
import com.ruoyi.cai.trd.ImDataRes;
import com.ruoyi.cai.trd.ImMsgGen;
import com.ruoyi.cai.ws.cache.CallerRoomCache;
import com.ruoyi.cai.ws.cache.RoomCtxCache;
import com.ruoyi.cai.ws.constant.HangUpEnums;
import com.ruoyi.cai.ws.dto.WsR;
import com.ruoyi.cai.ws.dto.WsRMsgGen;
import com.ruoyi.cai.ws.util.RoomWebSocketUtil;
import com.ruoyi.yunxin.Yunxin;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.bean.RoomData;
import com.ruoyi.cai.ws.bean.UserData;
import com.ruoyi.cai.ws.cache.OnlineDataCache;
import com.ruoyi.cai.ws.cache.RoomDataCache;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.Roman;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class SettleService {

    @Autowired
    private RoomService roomService;
    @Autowired
    private RoomDataCache roomDataCache;
    @Autowired
    private AccountService accountService;
    @Autowired
    private OnlineDataCache onlineDataCache;
    @Autowired
    private Yunxin yunxin;
    @Autowired
    private RoomCtxCache roomCtxCache;
    @Autowired
    private RedissonClient redissonClient;


    /**
     * 预扣费
     * @param roomId
     */
    public boolean withholdingFee(Long roomId){
        Room room = roomService.load(roomId);
        if(room == null || !room.isOnline()){
            log.warn("房间已经不存在或者不在线 无需预扣费 roomId={}",roomId);
            return false;
        }
        SettleService settleService = SpringUtil.getBean(SettleService.class);
        try {
            Long userId = room.getCallUserData().getId();
            Long price = room.getRoomData().getCallPrice();
            settleService.withholdingFeeUser(userId,price,room);
            return true;
        }catch (Exception e){
            log.error("预扣费失败！准备挂断电话",e);
            boolean b = roomService.hangUp(room.getRoomId());
            if(b){
                // 结算操作
                settleService.processOn(room.getRoomId());
            }
            // 向客户端发送挂断指令
            WsR r = WsRMsgGen.hangup("拨打方余额不足", room.getRoomId(), HangUpEnums.NOTMONEY.getCode());
            List<String> sessionKeys = roomCtxCache.getSessionKeysByRoomId(roomId);
            RoomWebSocketUtil.sendSendMessage(sessionKeys, r);
            roomService.closeAllFd(roomId);
            return false;
        }
    }

    /**
     * 预扣费业务操作
     */
    @Transactional(rollbackFor = Exception.class)
    public void withholdingFeeUser(Long userId,Long price,Room room){
        WithholdingFeeUserResp resp = accountService.withholdingFeeUser(userId, price);
        roomDataCache.incsBlackAmount(room.getRoomId(),resp.getDecrCoin(),resp.getDecrIncomeCoin());
    }


    /**
     * 结算处理
     */
    @SneakyThrows
    public void processOn(Long roomId){
        Room room = roomService.load(roomId);
        if(room == null){
            log.warn("房间不存在，无需结算 roomId={}",roomId);
            return;
        }
        String lock = LockManager.getVideoSettleLock(room.getRoomId());
        RLock clientLock = redissonClient.getLock(lock);
        boolean locked = clientLock.isLocked();
        if(locked){
            log.info("正在结算中，稍等！");
            return;
        }
        boolean lockFlag = clientLock.tryLock();
        if(!lockFlag){
            log.info("正在结算中，稍等！");
            return;
        }
        try {
            deal(room);
        }finally {
            clientLock.unlock();
        }

    }

    @Autowired
    private ConsumerManager consumerManager;

    /**
     * 结算内部整合逻辑
     * @param room
     */
    private void deal(Room room){
        if(room.isCanCall() || room.isSettle()){
            return;
        }
        if(!room.isReleaseRes()){ // 房间资源是否已经释放
            roomService.releaseRes(room.getRoomId());
        }
        Long roomId = room.getRoomId();
        // 未通话，无需结算
        if(room.getRoomData().getBeginTime() == null){
            roomDataCache.hMSet(roomId,"settleTime", DateUtil.currentSeconds());
            return;
        }
        VideoSettleResp resp = consumerManager.videoSettle(room);
        // 修改房间缓存
        Map<String,Object> map = new HashMap<>();
        map.put("payCoin",resp.getPayCoin());
        map.put("payIncome",resp.getPayIncome());
        map.put("settleTime", DateUtil.currentSeconds());
        roomDataCache.hMSet(roomId,map);
        // 移除在线房间状态
        onlineDataCache.remove(room.getRoomId());
        // 主叫方时长通知
        Long callTime = roomService.getCallTime(room);
        Long callId = room.getCallUserData().getId();
        Long receiveId = room.getReceiverUserData().getId();
        if(callTime > 0){
            ImDataRes imDataRes = ImMsgGen.callNotice(4, callId, receiveId, callTime);
            yunxin.sendToSync(callId,receiveId,imDataRes);
        }
        // 接收方通知
        Long anchorIncome = resp.getAnchorIncome();
        if(anchorIncome > 0){
            ImDataRes imDataRes = ImMsgGen.callNotice(4, receiveId, callId, callTime);
            yunxin.sendToSync(receiveId,callId,imDataRes);
            // 收入通知
//            ImMsgGen.videoIncome();
//            yunxin.sendTo(receiveId,null,)
        }
    }

}
