
package com.tmerclub.cloud.live.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.feign.SearchSpuFeignClient;
import com.tmerclub.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.tmerclub.cloud.api.multishop.vo.ShopDetailVO;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.api.user.vo.UserApiVO;
import com.tmerclub.cloud.common.cache.constant.CacheNames;
import com.tmerclub.cloud.common.cache.constant.LiveCacheNames;
import com.tmerclub.cloud.common.cache.util.RedisUtil;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.constant.SysTypeEnum;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageAdapter;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.product.constant.SpuStatus;
import com.tmerclub.cloud.common.product.dto.ProductSearchDTO;
import com.tmerclub.cloud.common.product.vo.search.SpuSearchVO;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.PrincipalUtil;
import com.tmerclub.cloud.live.constant.LiveRoomStatusType;
import com.tmerclub.cloud.live.dto.LiveRoomDTO;
import com.tmerclub.cloud.live.mapper.LiveRoomMapper;
import com.tmerclub.cloud.live.model.LiveRoom;
import com.tmerclub.cloud.live.service.LiveRoomProdService;
import com.tmerclub.cloud.live.service.LiveRoomService;
import com.tmerclub.cloud.live.vo.LiveRoomVO;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 直播间
 * @author TRACK
 */
@Service
public class LiveRoomServiceImpl implements LiveRoomService {

    @Autowired
    private LiveRoomMapper liveRoomMapper;
    @Autowired
    private LiveRoomProdService liveRoomProdService;
    @DubboReference
    private UserFeignClient userFeignClient;
    @DubboReference
    private SearchSpuFeignClient searchSpuFeignClient;
    @DubboReference
    private ShopDetailFeignClient shopDetailFeignClient;

    private static final Integer SEARCH_SPU = 2;
    private static final Integer SEARCH_NAME = 3;

    @Override
    public PageVO<LiveRoomVO> page(PageDTO pageDTO, LiveRoomDTO liveRoom) {
        if (StrUtil.isNotBlank(liveRoom.getNickName())) {
            // 搜索主播昵称
            setUserIds(liveRoom);
        }
        PageVO<LiveRoomVO> page = PageUtil.doPage(pageDTO, () -> liveRoomMapper.list(liveRoom));
        List<LiveRoomVO> liveRoomList = page.getList();
        if (CollUtil.isNotEmpty(liveRoomList)) {
            List<Long> userIds = liveRoomList.stream().map(LiveRoomVO::getUserId).toList();
            ServerResponseEntity<List<UserApiVO>> userResponse = userFeignClient.getUserByUserIds(userIds);
            if (!userResponse.isSuccess()) {
                throw new LuckException(userResponse.getMsg());
            }
            Map<Long, UserApiVO> userMap = userResponse.getData().stream().collect(Collectors.toMap(UserApiVO::getUserId, u -> u));
            for (LiveRoomVO liveRoomVO : liveRoomList) {
                UserApiVO userApiVO = userMap.get(liveRoomVO.getUserId());
                if (Objects.isNull(userApiVO)) {
                    liveRoomVO.setNickName("*用户已注销*");
                    liveRoomVO.setUserMobile("*用户已注销*");
                } else {
                    liveRoomVO.setNickName(userApiVO.getNickName());
                    liveRoomVO.setUserMobile(PhoneUtil.hideBetween(userApiVO.getPhone()).toString());
                }
            }
        }
        return page;
    }

    private void setUserIds(LiveRoomDTO liveRoom) {
        UserApiVO userApiVO = new UserApiVO();
        userApiVO.setNickName(liveRoom.getNickName());
        ServerResponseEntity<List<UserApiVO>> userResponse = userFeignClient.getUserByParam(userApiVO);
        if (!userResponse.isSuccess()) {
            throw new LuckException(userResponse.getMsg());
        }
        List<UserApiVO> userList = userResponse.getData();
        if (CollUtil.isNotEmpty(userList)) {
            List<Long> userIds = userList.stream().map(UserApiVO::getUserId).toList();
            liveRoom.setUserIds(userIds);
        }
    }

    @Override
    public LiveRoomVO getByRoomId(Long roomId) {
        LiveRoomVO liveRoom = liveRoomMapper.getByRoomId(roomId);
        if (Objects.isNull(liveRoom)) {
            throw new LuckException("直播间不存在，请刷新后重试");
        }
        if (Objects.equals(AuthUserContext.get().getSysType(), SysTypeEnum.MULTISHOP.value()) && !Objects.equals(liveRoom.getShopId(), AuthUserContext.get().getTenantId())) {
            throw new LuckException("权限不足");
        }
        ServerResponseEntity<UserApiVO> userResponse = userFeignClient.getUserData(liveRoom.getUserId());
        if (!userResponse.isSuccess()) {
            throw new LuckException(userResponse.getMsg());
        }
        UserApiVO userApiVO = userResponse.getData();
        if (Objects.isNull(userApiVO)) {
            // 该主播已经注销账号
            liveRoom.setNickName("*用户已注销*");
            liveRoom.setUserMobile("*用户已注销*");
            liveRoom.setStatus(-1);
        } else {
            liveRoom.setNickName(userApiVO.getNickName());
            liveRoom.setUserMobile(userApiVO.getPhone());
            liveRoom.setStatus(userApiVO.getStatus());
        }
        return liveRoom;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(LiveRoomDTO liveRoomDTO) {
        // 检查直播间信息，设置主播用户id
        checkLiveRoomAndSetUserId(liveRoomDTO, true);
        LiveRoom liveRoom = BeanUtil.map(liveRoomDTO, LiveRoom.class);
        liveRoom.setRoomId(null);
        liveRoom.setShopId(AuthUserContext.get().getTenantId());
        liveRoom.setLiveStatus(LiveRoomStatusType.NO_START.value());
        liveRoom.setRoomTop(0);
        liveRoomMapper.save(liveRoom);
        // 保存商品
        liveRoomProdService.save(liveRoom.getRoomId(), liveRoomDTO.getSpuIds());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = LiveCacheNames.LIVE_ROOM_INFO, key = "#liveRoomDTO.roomId")
    public void update(LiveRoomDTO liveRoomDTO) {
        LiveRoomVO dbLiveRoom = getByRoomId(liveRoomDTO.getRoomId());
        if (Objects.isNull(dbLiveRoom)) {
            throw new LuckException("直播间不存在，请刷新后重试");
        }
        if (!Objects.equals(dbLiveRoom.getShopId(), AuthUserContext.get().getTenantId())) {
            throw new LuckException("权限不足");
        }
        if (Objects.equals(dbLiveRoom.getLiveStatus(), LiveRoomStatusType.LIVING.value())) {
            throw new LuckException("直播已开始，无法修改信息");
        }
        if (Objects.equals(dbLiveRoom.getLiveStatus(), LiveRoomStatusType.OFFLINE.value())) {
            throw new LuckException("直播间已违规下架，无法修改信息");
        }
        if (!PrincipalUtil.isDbPhone(liveRoomDTO.getUserMobile(), dbLiveRoom.getUserMobile(), false)) {
            throw new LuckException("请输入正确的手机号");
        }
        if (liveRoomDTO.getUserMobile().contains(Constant.ASTERISK)) {
            liveRoomDTO.setUserMobile(dbLiveRoom.getUserMobile());
        }
        // 检查直播间信息，设置主播用户id
        checkLiveRoomAndSetUserId(liveRoomDTO, false);
        LiveRoom liveRoom = BeanUtil.map(liveRoomDTO, LiveRoom.class);
        liveRoom.setShopId(AuthUserContext.get().getTenantId());
        liveRoomMapper.update(liveRoom);
        // 更新商品
        liveRoomProdService.update(liveRoomDTO.getRoomId(), liveRoomDTO.getSpuIds());
    }

    @Override
    public void updateById(LiveRoom liveRoom) {
        liveRoomMapper.update(liveRoom);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = LiveCacheNames.LIVE_ROOM_INFO, key = "#roomId")
    public void deleteById(Long roomId) {
        Long shopId = AuthUserContext.get().getTenantId();
        LiveRoomVO liveRoom = getByRoomId(roomId);
        if (Objects.isNull(liveRoom)) {
            throw new LuckException("直播间不存在，请刷新后重试");
        }
        if (!Objects.equals(shopId, liveRoom.getShopId()) && !Objects.equals(Constant.PLATFORM_SHOP_ID, shopId)) {
            throw new LuckException("权限不足");
        }
        if (Objects.equals(liveRoom.getLiveStatus(), LiveRoomStatusType.LIVING.value())) {
            throw new LuckException("直播已开始，无法删除直播间");
        }
        liveRoomMapper.deleteById(roomId);
        // 删除直播间关联商品
        liveRoomProdService.delete(roomId);
    }

    @Override
    @CacheEvict(cacheNames = LiveCacheNames.LIVE_ROOM_INFO, key = "#liveRoomDTO.roomId")
    public void offline(LiveRoomDTO liveRoomDTO) {
        LiveRoomVO dbLiveRoom = getByRoomId(liveRoomDTO.getRoomId());
        if (Objects.isNull(dbLiveRoom)) {
            throw new LuckException("直播间不存在，请刷新后重试");
        }
        if (Objects.equals(dbLiveRoom.getLiveStatus(), LiveRoomStatusType.OFFLINE.value())) {
            throw new LuckException("直播间已违规下架，无法修改信息");
        }
        LiveRoom liveRoom = BeanUtil.map(dbLiveRoom, LiveRoom.class);
        liveRoom.setLiveStatus(LiveRoomStatusType.OFFLINE.value());
        liveRoom.setRemark(liveRoomDTO.getRemark());
        liveRoomMapper.update(liveRoom);
    }

    @Override
    public LiveRoomVO getByUserId(Long userId) {
        return liveRoomMapper.getLiveRoomInfo(userId, null);
    }

    @Override
    @Cacheable(cacheNames = LiveCacheNames.LIVE_ROOM_INFO, key = "#roomId")
    public LiveRoomVO getLivingRoomInfo(Long userId, Long roomId) {
        return liveRoomMapper.getLiveRoomInfo(userId, roomId);
    }

    @Override
    public PageVO<LiveRoomVO> pageRoomAndDetail(PageDTO pageDTO, LiveRoomDTO liveRoom) {
        PageVO<LiveRoomVO> page = new PageVO<>();
        if (Objects.equals(liveRoom.getSearchType(), SEARCH_SPU) && StrUtil.isNotBlank(liveRoom.getSpuName())) {
            // 搜索商品名
            setSpuIds(liveRoom);
            if (CollUtil.isEmpty(liveRoom.getSpuIds())) {
                page.setTotal(0L);
                page.setPages(0);
                page.setList(new ArrayList<>());
                return page;
            }
        }
        if (Objects.equals(liveRoom.getSearchType(), SEARCH_NAME) && StrUtil.isNotBlank(liveRoom.getNickName())) {
            // 搜索主播名称
            setUserIds(liveRoom);
            if (CollUtil.isEmpty(liveRoom.getUserIds())) {
                page.setTotal(0L);
                page.setPages(0);
                page.setList(new ArrayList<>());
                return page;
            }
        }
        List<LiveRoomVO> liveRoomList = liveRoomMapper.listRoomAndDetail(new PageAdapter(pageDTO), liveRoom);
        if (CollUtil.isNotEmpty(liveRoomList)) {
            Map<Long, SpuSearchVO> spuMap = getSpuMap(liveRoomList);
            Map<Long, String> shopMap = getShopMap(liveRoomList);
            for (LiveRoomVO liveRoomVO : liveRoomList) {
                String shopName = shopMap.get(liveRoomVO.getShopId());
                liveRoomVO.setShopName(shopName);
                if (CollUtil.isNotEmpty(liveRoomVO.getSpuList())) {
                    Iterator<SpuSearchVO> iterator = liveRoomVO.getSpuList().iterator();
                    while (iterator.hasNext()) {
                        SpuSearchVO spuSearchVO = iterator.next();
                        SpuSearchVO spu = spuMap.get(spuSearchVO.getSpuId());
                        if (Objects.isNull(spu)) {
                            iterator.remove();
                            continue;
                        }
                        spuSearchVO.setMainImgUrl(spu.getMainImgUrl());
                    }
                }
            }
        }
        page.setTotal(liveRoomMapper.countRoomAndDetail(liveRoom));
        page.setPages(PageUtil.getPages(page.getTotal(), pageDTO.getPageSize()));
        page.setList(liveRoomList);
        return page;
    }

    @Override
    public void updateLiveRoomStatus(Integer liveStatus, List<Long> roomIds) {
        liveRoomMapper.updateLiveRoomStatus(liveStatus, roomIds);
        delCache(roomIds);
    }

    @Override
    public void unableLiveRoom(Long userId) {
        if (Objects.isNull(userId)) {
            return;
        }
        List<Long> roomIds = liveRoomMapper.listNeedStopLiveRoom(userId);
        if (CollUtil.isEmpty(roomIds)) {
            return;
        }
        liveRoomMapper.updateLiveRoomStatus(LiveRoomStatusType.STOP.value(), roomIds);
        // 清除缓存
        List<String> keys = new ArrayList<>();
        for (Long roomId : roomIds) {
            keys.add(LiveCacheNames.LIVE_ROOM_INFO + CacheNames.UNION + roomId);
        }
        RedisUtil.del(keys);
    }

    @Override
    public List<Long> listRoomIdsByShopId(List<Long> shopIds) {
        return liveRoomMapper.listRoomIdsByShopId(shopIds);
    }

    private static void delCache(List<Long> roomIds) {
        List<String> keys = new ArrayList<>();
        for (Long roomId : roomIds) {
            keys.add(LiveCacheNames.LIVE_ROOM_INFO + CacheNames.UNION + roomId);
        }
        RedisUtil.del(keys);
    }

    private Map<Long, String> getShopMap(List<LiveRoomVO> liveRoomList) {
        List<Long> shopIds = liveRoomList.stream().map(LiveRoomVO::getShopId).toList();
        ServerResponseEntity<List<ShopDetailVO>> shopResponse = shopDetailFeignClient.listByShopIds(shopIds);
        if (!shopResponse.isSuccess()) {
            throw new LuckException(shopResponse.getMsg());
        }
        Map<Long, String> shopMap = shopResponse.getData().stream().collect(Collectors.toMap(ShopDetailVO::getShopId, ShopDetailVO::getShopName));
        return shopMap;
    }

    private Map<Long, SpuSearchVO> getSpuMap(List<LiveRoomVO> liveRoomList) {
        Set<Long> spuIdSet = new HashSet<>(Constant.INITIAL_CAPACITY);
        for (LiveRoomVO liveRoomVO : liveRoomList) {
            List<Long> spuIds = liveRoomVO.getSpuList().stream().map(SpuSearchVO::getSpuId).toList();
            spuIdSet.addAll(spuIds);
        }
        // 搜索商品名称
        ProductSearchDTO productSearchDTO = new ProductSearchDTO();
        productSearchDTO.setSpuIds(new ArrayList<>(spuIdSet));
        productSearchDTO.setSpuStatus(SpuStatus.PUT_SHELF.value());
        ServerResponseEntity<List<SpuSearchVO>> spuResponse = searchSpuFeignClient.simpleList(productSearchDTO);
        if (!spuResponse.isSuccess()) {
            throw new LuckException(spuResponse.getMsg());
        }
        List<SpuSearchVO> spuList = spuResponse.getData();
        Map<Long, SpuSearchVO> spuMap = spuList.stream().collect(Collectors.toMap(SpuSearchVO::getSpuId, s -> s));
        return spuMap;
    }

    private void setSpuIds(LiveRoomDTO liveRoom) {
        // 搜索商品名称
        ProductSearchDTO productSearchDTO = new ProductSearchDTO();
        productSearchDTO.setSpuName(liveRoom.getSpuName());
        productSearchDTO.setSpuStatus(SpuStatus.PUT_SHELF.value());
        ServerResponseEntity<List<SpuSearchVO>> spuResponse = searchSpuFeignClient.simpleList(productSearchDTO);
        if (!spuResponse.isSuccess()) {
            throw new LuckException(spuResponse.getMsg());
        }
        List<SpuSearchVO> spuList = spuResponse.getData();
        List<Long> spuIds = spuList.stream().map(SpuSearchVO::getSpuId).toList();
        liveRoom.setSpuIds(spuIds);
    }

    private void checkLiveRoomAndSetUserId(LiveRoomDTO liveRoomDTO, boolean isSave) {
        // 校验时间
        Date startTime = liveRoomDTO.getStartTime();
        Date endTime = liveRoomDTO.getEndTime();
        if (isSave) {
            if (DateUtil.compare(new Date(), startTime) > 0) {
                throw new LuckException("开始时间不能少于当前时间");
            }
            if (DateUtil.compare(startTime, endTime) > 0) {
                throw new LuckException("开始时间不能大于结束时间");
            }
            boolean expiredEndTime = DateUtil.isIn(endTime, startTime, DateUtil.offsetMinute(startTime, 30)) ||
                    !DateUtil.isIn(endTime, startTime, DateUtil.offsetHour(startTime, 24));
            if (expiredEndTime) {
                throw new LuckException("开始和结束时间间隔必须大于30分钟，不得超过24小时");
            }
        }
        // 校验主播信息
        if (StrUtil.isBlank(liveRoomDTO.getNickName()) || StrUtil.isBlank(liveRoomDTO.getUserMobile())) {
            throw new LuckException("主播信息不能为空");
        }
        UserApiVO userApiVO = new UserApiVO();
        userApiVO.setNickName(liveRoomDTO.getNickName());
        userApiVO.setUserMobile(liveRoomDTO.getUserMobile());
        userApiVO.setStatus(StatusEnum.ENABLE.value());
        ServerResponseEntity<List<UserApiVO>> userResponse = userFeignClient.getUserByParam(userApiVO);
        if (!userResponse.isSuccess()) {
            throw new LuckException(userResponse.getMsg());
        }
        List<UserApiVO> userList = userResponse.getData();
        if (CollUtil.isEmpty(userList) || !Objects.equals(userList.get(0).getNickName(), liveRoomDTO.getNickName())) {
            throw new LuckException("当前选择的主播不存在或被禁用，请检查主播信息是否正确");
        }
        Long userId = userList.get(0).getUserId();
        liveRoomDTO.setUserId(userId);
        // 商家不能在一个时间段创建两个直播间
        int countByShop = liveRoomMapper.countRoomByParam(liveRoomDTO.getShopId(), null, liveRoomDTO.getRoomId(), startTime, endTime);
        if (countByShop > 0) {
            throw new LuckException("该时间段下已设有直播间，无法再配置新的直播间");
        }
        // 一个主播账号不能同时开播两场直播
        int countByUser = liveRoomMapper.countRoomByParam(null, userId, liveRoomDTO.getRoomId(), startTime, endTime);
        if (countByUser > 0) {
            throw new LuckException("主播在该时间段下已设有直播间，无法再配置新的直播间");
        }
    }
}
