package com.tzy.controller.living;

import com.beust.jcommander.internal.Lists;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tzy.annotation.ApiLimitRule;
import com.tzy.common.config.CommonConfig;
import com.tzy.common.config.handle.ApiVersion;
import com.tzy.common.constant.Constants;
import com.tzy.common.core.controller.BaseController;
import com.tzy.common.dto.InDto;
import com.tzy.common.dto.OutDTO;
import com.tzy.common.dto.UserInfo;
import com.tzy.common.utils.UserType;
import com.tzy.common.utils.UserUtils;
import com.tzy.common.utils.bean.JSONTools;
import com.tzy.common.utils.http.forest.CommonForestClient;
import com.tzy.dto.*;
import com.tzy.framework.util.RedisUtils;
import com.tzy.liveConfig.service.LiveLikeDBUpdateService;
import com.tzy.liveConfig.service.LiveLikePushService;
import com.tzy.sportcard.api.dto.LiveMerchantDTO;
import com.tzy.sportcard.api.dto.group.LiveListDTO;
import com.tzy.sportcard.api.service.GroupApiService;
import com.tzy.sportcard.group.domain.CardGroupLivesConfig;
import com.tzy.sportcard.group.domain.CardGroupLivesLike;
import com.tzy.sportcard.group.mapper.CardGroupLivesConfigMapper;
import com.tzy.sportcard.group.mapper.CardGroupLivesLikeMapper;
import com.tzy.sportcard.group.service.ICardGroupLivesConfigService;
import com.tzy.sportcard.group.service.impl.GroupActService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.teasoft.bee.osql.SuidRich;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 直播-api
 */
@Api("直播-api")
@Slf4j
@RestController
@RequestMapping("/api/living")
public class LivingApiController extends BaseController {
    @Resource
    private SuidRich suidRich;
    @Resource
    private CardGroupLivesConfigMapper cardGroupLivesConfigMapper;
    @Resource
    private CardGroupLivesLikeMapper cardGroupLivesLikeMapper;
    @Resource
    private GroupApiService groupApiService;
    @Resource
    private LiveLikePushService liveLikePushService;
    @Resource
    private LiveLikeDBUpdateService liveLikeDBUpdateService;
    @Resource
    private ICardGroupLivesConfigService livesConfigService;
    @Resource
    private CommonForestClient commonForestClient;
    @Value("${liveWebSocketUrl:https://im-dev.hobbystocks.cn/chat/handler}")
    private String liveWebSocketUrl;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private GroupActService groupActService;

    @PostMapping(value = "/details")
    public OutDTO details(@RequestBody InDto inDto) {
        Integer roomid = inDto.getIntegerParam("id");
        if (null == roomid) return OutDTO.error(10040, "参数[id]不能为空!");
        LivingRoomDTO cond = new LivingRoomDTO();
        cond.setId(roomid);
        LivingRoomDTO livingRoomDto = suidRich.selectOne(cond);
        if (livingRoomDto == null) {
            return OutDTO.error500("直播间不存在!");
        }
        return OutDTO.ok().put("livingRoomInfo", livingRoomDto);
    }


    @ApiOperation("获取直播间")
    @PostMapping("/{version}/list/{type}/{refId}")
    public OutDTO findMerchantLiving(@PathVariable("refId") Integer refId, @PathVariable("type") String type) {
        UserInfo user = UserUtils.getSimpleUserInfo();
        Integer userId = user == null ? null : user.getId();
        List<LiveListDTO> liveList = livesConfigService.findAllLiving(type, refId, userId);
        if (CollectionUtils.isEmpty(liveList)) {
            return OutDTO.ok().put("livingList", liveList);
        }

        boolean isShipping = user != null && UserType.USER_ROLE_SHIPPING.equals(user.getRoleCode());
        // 判断当前登陆的用户是否是商家角色
        Integer merchantId = isShipping && user.getMerchantId() != null ? user.getMerchantId() : null;
        liveList.parallelStream().filter(living -> Constants.ORDER_TYPE_GROUP.equals(living.getCategory()))
                .forEach(living -> {
                    boolean confirmStatus = isShipping && Objects.equals(living.getMerchantId(), merchantId);
                    living.setConfirmStatus(confirmStatus);
                    groupApiService.setGroupData(userId, living);
                });
        return OutDTO.ok().put("livingList", liveList);
    }

    @ApiOperation("获取已结束直播")
    @PostMapping("/{version}/end/list")
    public OutDTO findEndLive(@RequestBody EndLiveParam endLiveParam) {
        PageInfo<LiveListDTO> liveList = livesConfigService.findEndLives(endLiveParam);
        return OutDTO.ok().put("livingList", liveList);
    }


    @ApiOperation("获取直播间用户信息")
    @PostMapping("/{version}/user/{code}")
    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
    public OutDTO findLivingRoomUser(@PathVariable("code") String code) {
        List<LivingRoomDTO> rooms = getRooms(code);
        if (CollectionUtils.isEmpty(rooms)) {
            return OutDTO.ok().put("users", new ArrayList<>());
        }
        Integer merchantId = rooms.get(0).getMerchantId();
        String url = String.format(CommonConfig.baseconfig.getImBaseUrl() + CommonConfig.baseconfig.getImUserUrl(), code);
        String result = commonForestClient.sendGet(url);
        ImUserResp resp = JSONTools.jsonStr2obj(result, ImUserResp.class);
        if (resp == null || resp.getCode() != 200 || CollectionUtils.isEmpty(resp.getData())) {
            log.warn("查询直播间用户异常:{}", result);
            return OutDTO.ok().put("users", new ArrayList<>());
        }
        UserInfo user = UserUtils.getSimpleUserInfo();
        boolean isOwnerMerchant = user != null && Objects.equals(merchantId, user.getMerchantId());
        log.debug("查询直播间用户结果:{}", result);
        List<ImUserDTO> users = livesConfigService.findLivingRoomUser(merchantId, resp.getData(), isOwnerMerchant, 1, 200);
        return OutDTO.ok().put("users", users);
    }

    private List<LivingRoomDTO> getRooms(String code) {
        LivingRoomDTO cond = new LivingRoomDTO();
        cond.setCode(code);
        cond.setDelFlg(0);
        cond.setStatus(1);
        return suidRich.select(cond);
    }

    private LivingRoomDTO checkRoomUser(ImParam param) {
        if (StringUtils.isEmpty(param.getCode())) {
            return null;
        }
        if (CollectionUtils.isEmpty(param.getUserIds())) {
            return null;
        }
        List<LivingRoomDTO> rooms = getRooms(param.getCode());
        if (CollectionUtils.isEmpty(rooms)) {
            return null;
        }
        return rooms.get(0);
    }

    @ApiOperation("直播间用户变动")
    @PostMapping("/{version}/user/change")
    public OutDTO livingUserChange(@RequestBody ImParam param) {
        LivingRoomDTO livingRoom = checkRoomUser(param);
        if (livingRoom == null) {
            return OutDTO.error(405, "直播间信息不存在");
        }
        log.debug("直播间用户变动:{}", param);
        List<ImUserDTO> users = livesConfigService.getImUsers(livingRoom.getMerchantId(), param.getUserIds(), 3);
        livesConfigService.setCachedLiveRoomUser(param.getCode(), param.getUserIds());

        if (CollectionUtils.isEmpty(users)) {
            return OutDTO.ok();
        }
//        if (!redisUtils.setIfAbsent(Constants.LIVING_USER_CHANGE_RECORD + param.getCode(), "1", 2, TimeUnit.SECONDS)) {
//            return OutDTO.ok();
//        }
        //List<String> imgList = new ArrayList<>(3);
        // StringJoiner stringJoiner = new StringJoiner(",");
        // for(ImUserDTO user:users){
        //     stringJoiner.add(user.getId().toString());
        //     imgList.add(user.getAvatar());
        // }
        // String currentUserIds = stringJoiner.toString();
        // String key=Constants.LIVING_ROOM_USER_KEY+param.getCode();
        // Object existUserId = redisUtils.get(key);
        // if (currentUserIds.equals(existUserId)) {
        //     return OutDTO.ok();
        // }
        List<String> imgList = users.stream().map(ImUserDTO::getAvatar).collect(Collectors.toList());
        Message message = buildImReq(param.getCode(), imgList, param.getUserIds());
        //commonForestClient.sendPost(liveWebSocketUrl, Constants.JSON_HEADS, message);
        //redisUtils.set(key,currentUserIds,60);
        return OutDTO.ok().put("message",message);
    }

    private Message buildImReq(String code, List<String> imgList, List<Integer> userIdList) {
        Map<String, Object> body = new HashMap<>(2);
        body.put("imgList", imgList);
        body.put("totalNum", userIdList.size());
        return Message.builder().code("chat")
                .messageType("chat_to_room")
                .messageParam(
                        Message.MessageParam.builder()
                                .receiver(code)
                                .payload(
                                        Message.MessageParam.Payload.builder()
                                                .contentType("CHANGES_NUM_PEOPLE")
                                                .sender("app")
                                                .content("user")
                                                .extra(JSONTools.obj2json(body))
                                                .build()
                                ).build()).build();
    }


    @ApiOperation("获取直播间用户信息v2,分页")
    @PostMapping("/{version}/user")
    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
    public OutDTO findLivingRoomUserV2(@Validated @RequestBody LivingUserParam param) {
        String code = param.getCode();
        if (StringUtils.isEmpty(code)) {
            return OutDTO.error500("参数缺失");
        }
        List<LivingRoomDTO> rooms = getRooms(code);
        if (CollectionUtils.isEmpty(rooms)) {
            return OutDTO.ok().put("users", new ArrayList<>()).put("totalNum", 0);
        }
        Integer merchantId = rooms.get(0).getMerchantId();
        // String url = String.format(CommonConfig.baseconfig.getImBaseUrl() + CommonConfig.baseconfig.getImUserUrl(), code);
        // String result = commonForestClient.sendGet(url);
        String result = livesConfigService.getCachedLiveRoomUser(param.getCode());
        if (result == null) {
            log.warn("查询直播间用户异常:{}", result);
            return OutDTO.ok().put("users", new ArrayList<>()).put("totalNum", 0);
        }
        List<Integer> userIds = JSONTools.jsonStr2obj(result, List.class);
        UserInfo user = UserUtils.getSimpleUserInfo();
        boolean isOwnerMerchant = user != null && Objects.equals(merchantId, user.getMerchantId());
        log.debug("查询直播间用户结果:{}", result);
        List<ImUserDTO> users = livesConfigService.findLivingRoomUser(merchantId, userIds, isOwnerMerchant, param.getPageNo(), param.getPageSize());
        return OutDTO.ok().put("users", users).put("totalNum", userIds.size());
    }

    @ApiOperation("获取商城直播画面")
    @PostMapping("/{version}/screen")
    public OutDTO getlivingScreen() {
        // 查询直播中的商城直播
        List<CardGroupLivesConfig> shopLivings = livesConfigService.getShopLivings();
        if(CollectionUtils.isEmpty(shopLivings)){
            return OutDTO.ok().put("livingScreens", null);
        }
        List<LivingScreenDTO> livingScreens = Lists.newArrayList();
        shopLivings.forEach(living ->{
            String key = "simple_living_" + living.getCode();
            if(redisUtils.hasKey(key)){
                LivingScreenDTO livingScreenDTO = new LivingScreenDTO();
                Map<Object, Object> playbackData = redisUtils.hmget(key);
                livingScreenDTO.setCaptureTime(playbackData.get("capture_time").toString());
                livingScreenDTO.setCaptureUrl(playbackData.get("capture_url").toString());
                livingScreenDTO.setCode(living.getCode());
                livingScreens.add(livingScreenDTO);
            }
        });
        return OutDTO.ok().put("livingScreens", livingScreens);
    }

    @ApiOperation("获取直播间点赞")
    @PostMapping("/{version}/like/{code}")
    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
    public OutDTO getLivingRoomLike(@PathVariable("code") String code) {
        if (!redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_KEY, code)) {
            List<CardGroupLivesConfig> livingRoomDto = cardGroupLivesConfigMapper.selectLivingRoomByCode(code);
            // 写缓存
            int liveLikeNum = 0;
            if(livingRoomDto != null && !livingRoomDto.isEmpty()){
                liveLikeNum = livingRoomDto.get(0).getLiveLikeNum();
            }
            redisUtils.hset(Constants.LIVING_ROOM_LIKE_KEY, code, liveLikeNum, 24 * 60 * 60);
        }
        return OutDTO.ok().put("count", redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, code));
    }

    @ApiOperation("点赞直播间")
    @PostMapping("/{version}/like")
    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
    public OutDTO likeLivingRoom(@Validated @RequestBody UserLikeParam param) {
        //1000465 HS-APP【直播间竞价】并发场景下当前端传的num参数大于50时，则接口最大有效值为50（防止被恶意修改参数）
        int likeNum = param.getNum() >= 50 ? 50 : param.getNum();
        //region LIVING_ROOM_LIKE_KEY logic
        int finalLikeNum = likeNum;
        if (redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_KEY, param.getCode())) {
            finalLikeNum = (int)redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, param.getCode()) +finalLikeNum;
        }
        else{
            List<CardGroupLivesConfig> livingRoomDtoList = cardGroupLivesConfigMapper.selectLivingRoomByCode(param.getCode());
            if(livingRoomDtoList != null && !livingRoomDtoList.isEmpty()){
                finalLikeNum = (livingRoomDtoList.get(0).getLiveLikeNum()==null?0:livingRoomDtoList.get(0).getLiveLikeNum()) + likeNum;
            }
        }
        // 写LIVING_ROOM_LIKE_KEY缓存
        redisUtils.hset(Constants.LIVING_ROOM_LIKE_KEY, param.getCode(), finalLikeNum, 24 * 60 * 60);
        //endregion

        //region LIVING_ROOM_LIKE_USER_KEY logic
        UserInfo user = UserUtils.getSimpleUserInfo(true);
        // 写LIVING_ROOM_LIKE_USER_KEY缓存
        int finalUserLikeNum = likeNum;
        if (redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode())) {
            finalUserLikeNum = (int)redisUtils.hget(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode()) +finalUserLikeNum;
        }
        else{
            CardGroupLivesLike livesLike = cardGroupLivesLikeMapper.selectCardGroupLivesLikeById(user.getId(),param.getCode());
            if (livesLike != null) {
                finalUserLikeNum = livesLike.getLike_num()==null?0:livesLike.getLike_num() + likeNum;
            }
        }
        // 写LIVING_ROOM_LIKE_USER_KEY缓存
        redisUtils.hset(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode(), finalUserLikeNum, 24 * 60 * 60);
        //endregion
        // 定时推给db更新
        liveLikeDBUpdateService.handleRequest(param.getCode(),user.getId());
        // 定时推给im更新
        liveLikePushService.handleRequest(param.getCode());


        return OutDTO.ok().put("count", finalLikeNum);
    }

    @ApiOperation("首页直播商家排序")
    @PostMapping("/{version}/sorts")
    public OutDTO getLiveMerchantList(@RequestBody CardGroupLivesConfig cardGroupLivesConfig) {
        if(cardGroupLivesConfig == null){
            cardGroupLivesConfig = new CardGroupLivesConfig();
        }
        UserInfo userInfo = UserUtils.getSimpleUserInfo(false);
        if(userInfo != null){
            cardGroupLivesConfig.setAppUserId(userInfo.getId());
        }
        // 查询直播中的商家直播信息
        List<LiveMerchantDTO> liveMerchantList = livesConfigService.getLiveMerchantList(cardGroupLivesConfig);
        return OutDTO.ok().put("liveMerchantList", liveMerchantList);
    }

    @ApiVersion(1.0)
    @ApiOperation("根据paniniListId查询直播中的商品/拍品")
    @PostMapping("/{version}/panini/{paniniListId}")
    public OutDTO getLiveByPaniniListId(@PathVariable Long paniniListId) {
        // 根据paniniListId查询直播中的商品
        List<LiveMerchantDTO> paniniLives = livesConfigService.getLiveByPaniniListId(paniniListId);
        return OutDTO.ok().put("paniniLives", paniniLives);
    }

    @PostMapping("/{version}/main/place/list")
    @ApiVersion(1.0)
    @ApiOperation(value = "查询双11主会场直播列表")
    public OutDTO getMainPlaceLiveConfigs(@RequestBody InDto inDto){
        PageHelper.startPage(inDto.getPageNo(),inDto.getPageSize());
        List<LiveListDTO> livesConfigList = livesConfigService.getLivesByStartTime();
        return OutDTO.ok().put("livesConfigList",livesConfigList);
    }
}
