package com.platform.modules.live.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.platform.common.utils.MapUtils;
import com.platform.common.utils.R;
import com.platform.common.utils.RedisContants;
import com.platform.common.utils.RedisUtils;
import com.platform.modules.foreign.entity.SceneStreamForeignEntity;
import com.platform.modules.live.constants.SceneConstants;
import com.platform.modules.live.dao.LiveSceneLiveInfoDao;
import com.platform.modules.live.entity.*;
import com.platform.modules.live.service.*;
import com.platform.modules.live.utils.ForeignProperties;
import com.platform.modules.live.vo.LiveCasterSubVo;
import com.platform.modules.live.vo.LiveInfoVo;
import com.platform.modules.plm.util.MaterialUtils;
import com.platform.modules.sys.entity.SysUserEntity;
import com.platform.modules.sys.service.SysUserService;
import com.platform.plugs.live.enums.PushStreamStatus;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Service("liveSceneLiveInfoService")
@Transactional
public class LiveSceneLiveInfoServiceImpl extends ServiceImpl<LiveSceneLiveInfoDao, LiveSceneLiveInfoEntity> implements LiveSceneLiveInfoService {

    private final Log log = LogFactory.getLog(LiveSceneLiveInfoServiceImpl.class);
    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private LiveSceneService liveSceneService;

    @Autowired
    private LiveSceneLiveInfoExtService liveSceneLiveInfoExtService;

    @Autowired
    private LiveSceneLiveInfoRecordService liveSceneLiveInfoRecordService;

    @Autowired
    private LiveSceneRecordService liveSceneRecordService;
    @Autowired
    private ForeignProperties foreignProperties;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public void save(LiveSceneLiveInfoEntity liveSceneLiveInfo) {
        this.baseMapper.insert(liveSceneLiveInfo);
    }

    @Override
    public void saveOrUpdate(Integer sceneId, List<Integer> userIdList) {
        //先删除现场与人员关系
        this.deleteByMap(new MapUtils().put("scene_id", sceneId));

        if (userIdList == null || userIdList.size() == 0) {
            return;
        }

        //保存现场与人员关系
        List<LiveSceneLiveInfoEntity> list = new ArrayList<>(userIdList.size());
        LiveSceneLiveInfoEntity tmpInfo = null;
        for (Integer uId : userIdList) {
            tmpInfo = new LiveSceneLiveInfoEntity();
            tmpInfo.setSceneId(sceneId);
            tmpInfo.setUserId(uId);

            list.add(tmpInfo);
        }
        this.insertBatch(list);
    }

    @Override
    public void update(LiveSceneLiveInfoEntity liveSceneLiveInfo) {
        this.baseMapper.update(liveSceneLiveInfo, null);
    }

    @Override
    public void delete(Integer id) {
        this.baseMapper.deleteById(id);
    }

    @Override
    public void deleteBatch(Integer[] ids) {
        this.baseMapper.deleteBatchIds(Arrays.asList(ids));
    }


    @Override
    public R startScenePush(Integer userId, Integer sceneId) {

        if (userId == null || sceneId == null) {
            return R.error("参数错误：userId -> " + userId + " sceneId -> " + sceneId);
        }
        // 校验现场是否已结束
        LiveSceneEntity live = liveSceneService.selectById(sceneId);
        if (live == null || SceneConstants.SCENE_PROD != live.getSceneState()) {
            log.error("can not find LiveSceneEntity by sceneId : " + sceneId + " or live has been not checked");
            return R.error("找不到现场或现场未审核");
        }

        LiveSceneLiveInfoEntity liveInfo = this.selectOne(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", sceneId).eq("user_id", userId));
        if (liveInfo == null) {
            log.error("can not find LiveSceneLiveInfoEntity by sceneId : " + sceneId + " and userId : " + userId);
            return R.error("找不到现场流");
        }
//        Date now = new Date();
//        liveInfo.setPushStart(now);
        liveInfo.setPushState(SceneConstants.PushEnum.PUSHING.getState());

        LiveSceneLiveInfoExtEntity infoExtEntity = liveSceneLiveInfoExtService.selectOne(
                new EntityWrapper<LiveSceneLiveInfoExtEntity>().eq("info_id", liveInfo.getId()));
        this.baseMapper.updateById(liveInfo);
        liveInfo.setExtEntity(infoExtEntity);

        // 若为记者流，则修改记者状态为推流状态
        if (null != liveInfo.getUserId()){
            redisUtils.set(RedisContants.REPORTER_PUSH_STATE + liveInfo.getUserId(), 1, -1);
        }

        // 向导播台推送消息
//		LiveCasterSubVo vo = new LiveCasterSubVo(sceneId, userId,  user == null ? userId.toString() : user.getRealname(), infoExtEntity.getPushUrl(), infoExtEntity.getPlayUrlRmtp(), infoExtEntity.getPlayUrlHls(), infoExtEntity.getPlayUrlFlv());
//		simpMessagingTemplate.convertAndSend(SceneConstants.LIVE_CASTER_SUB_URL + "/" + sceneId, vo);
        return R.ok().put("liveInfo", liveInfo);
    }

    @Override
    public R stopScenePush(Integer userId, Integer sceneId) {
        if (userId == null || sceneId == null) {
            return R.error("参数错误：userId -> " + userId + " sceneId -> " + sceneId);
        }
        LiveSceneLiveInfoEntity liveInfo = this.selectOne(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", sceneId).eq("user_id", userId));
        if (liveInfo == null) {
            log.error("can not find LiveSceneLiveInfoEntity by sceneId : " + sceneId + " and userId : " + userId);
            return R.error("找不到现场流");
        }
//        Date now = new Date();
//        liveInfo.setPushEnd(now);
        liveInfo.setPushState(SceneConstants.PushEnum.STOP.getState());
        this.baseMapper.updateById(liveInfo);

        // 若为记者流，则修改记者在线状态
        if (null != liveInfo.getUserId()){
            redisUtils.delete(RedisContants.REPORTER_PUSH_STATE + liveInfo.getUserId());
        }

        return R.ok().put("msg", "操作成功");
    }

    @Override
    @Transactional(readOnly = true)
    public List<LiveCasterSubVo> selectListBySceneId(Integer sceneId) {
        List<LiveCasterSubVo> result = new ArrayList<>();
        List<LiveSceneLiveInfoEntity> list = this.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", sceneId));

        if (list == null || list.size() <= 0) return result;
        for (LiveSceneLiveInfoEntity entity : list) {
            LiveSceneLiveInfoExtEntity infoExtEntity = liveSceneLiveInfoExtService.selectOne(
                    new EntityWrapper<LiveSceneLiveInfoExtEntity>().eq("info_id", entity.getId()));
            if (infoExtEntity == null) {
                continue;
            }
            Integer userId = entity.getUserId();
            SysUserEntity user = null;
            if (null != userId) {
                user = sysUserService.selectBaseById(Long.valueOf(userId));
            }
            LiveCasterSubVo vo = new LiveCasterSubVo(sceneId, userId, user == null ? userId + "" : user.getRealname(), infoExtEntity.getPushUrl(), infoExtEntity.getPlayUrlRmtp(), infoExtEntity.getPlayUrlHls(), infoExtEntity.getPlayUrlFlv());
            result.add(vo);
        }
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public LiveSceneLiveInfoEntity findLiveInfoByPushDomainAppAndStream(String domain, String appName, String streamName) {
        List<LiveSceneLiveInfoEntity> list = this.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("push_domain", domain).eq("app_name", appName).eq("stream_name", streamName));
        if (list == null || list.size() <= 0) return null;
        return list.get(0);
    }

    @Override
    @Transactional(readOnly = true)
    public LiveSceneLiveInfoEntity findLiveInfoByLiveDomainAppAndStream(String domain, String appName, String streamName) {
        List<LiveSceneLiveInfoEntity> list = this.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("live_domain", domain).eq("app_name", appName).eq("stream_name", streamName));
        if (list == null || list.size() <= 0) return null;
        return list.get(0);
    }

    @Override
    public void saveLiveInfoRecord(LiveSceneLiveInfoRecordEntity liveInfoRecord) {
        LiveSceneLiveInfoEntity obj = findLiveInfoByLiveDomainAppAndStream(liveInfoRecord.getDomain(), liveInfoRecord.getAppName(), liveInfoRecord.getStreamName());
        Integer sceneId = null;
        if (obj == null) {
            log.error("saveLiveInfoRecord error : can not find LiveInfo by : " + liveInfoRecord.getDomain() + "/" + liveInfoRecord.getAppName() + "/" + liveInfoRecord.getStreamName());
        } else {
            liveInfoRecord.setInfoId(obj.getId());
            liveInfoRecord.setInfoName(obj.getInfoName());
            sceneId = obj.getSceneId();
        }
        //生成流录制记录
        liveSceneLiveInfoRecordService.insert(liveInfoRecord);
//		if(sceneId == null) return ;
        //生成直播回顾
        Date now = new Date();
        LiveSceneRecordEntity liveSceneRecordEntity = new LiveSceneRecordEntity();
        liveSceneRecordEntity.setCreateDate(now);
        liveSceneRecordEntity.setLastUpdateDate(now);
        liveSceneRecordEntity.setSceneId(sceneId);
        liveSceneRecordEntity.setRecordName(liveInfoRecord.getInfoName());
        if (obj != null)
            liveSceneRecordEntity.setTitleImage(obj.getTitleImage());
        liveSceneRecordEntity.setUri(liveInfoRecord.getUri());
        liveSceneRecordEntity.setDuration(liveInfoRecord.getDuration());
        liveSceneRecordEntity.setStartTime(liveInfoRecord.getStartTime());
        liveSceneRecordEntity.setStopTime(liveInfoRecord.getStopTime());
        liveSceneRecordEntity.setRecordStatus(SceneConstants.RECORD_TO_SHOW);
        liveSceneRecordEntity.setIsDelete(SceneConstants.NOT_DELETE);

        liveSceneRecordService.insert(liveSceneRecordEntity);
        //更改数据库状态
        //上传至媒体库?
        //删除oss？
        //拉取至本地
    }

    @Override
    public void updateLiveState(LiveSceneLiveInfoEntity liveInfoEntity, String action, Integer time) {
        //记者推流不更改状态，通过app调用接口实现状态变化
//		if(SceneConstants.InfoTypeEnum.REPORTER.getType() == liveInfoEntity.getInfoType()) return;
        if (PushStreamStatus.publish.toString().equals(action)) {
//			if(liveInfoEntity.getPushStart() == null)
            // 仅记录最后推流的开始结束时间
            liveInfoEntity.setPushStart(new Date(Long.parseLong(time + "000")));
            liveInfoEntity.setPushState(SceneConstants.PushEnum.PUSHING.getState());
        } else {
            liveInfoEntity.setPushEnd(new Date(Long.parseLong(time + "000")));
            liveInfoEntity.setPushState(SceneConstants.PushEnum.STOP.getState());
        }
        updateById(liveInfoEntity);
    }

    @Override
    /**
     * 根据现场ID获取现场对外流信息
     */
    @Transactional(readOnly = true)
    public List<SceneStreamForeignEntity> selectLiveInfoForeign(Integer sceneId) {
        if (null == sceneId) {
            return null;
        }
        List<SceneStreamForeignEntity> list = this.baseMapper.selectLiveInfoForeign(sceneId);
        if (null != list && list.size() > 0) {
            for (SceneStreamForeignEntity stream : list) {
                if (StringUtils.isNotBlank(stream.getCoverUrl())) {
                    stream.setCoverUrl(MaterialUtils.getMaterialUrl(stream.getCoverUrl(), foreignProperties.getMediaurl()));
                }
            }
        }
        return list;
    }

    @Override
    public void priority(Integer[] ids, Integer[] prioritys) {
        if (ids == null || ids.length == 0 || prioritys == null || prioritys.length == 0) {
            return;
        }
        for (int i = 0; i < ids.length; i++) {
            if (ids[i] != null && prioritys[i] != null) {
                LiveSceneLiveInfoEntity entity = new LiveSceneLiveInfoEntity();
                entity.setPriority(prioritys[i]);
                entity.setId(ids[i]);
                this.baseMapper.updateById(entity);
            }
        }
    }

    /**
     * 检查确认现场下是否存在用户流信息
     *
     * @param sceneId 现场ID
     * @param userId  用户ID
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public boolean existInfo(Integer sceneId, Integer userId) {
        if (null == sceneId || null == userId) {
            return false;
        }
        EntityWrapper<LiveSceneLiveInfoEntity> ew = new EntityWrapper<>();
        ew.eq("scene_id", sceneId);
        ew.eq("user_id", userId);
        int count = this.selectCount(ew);
        if (count > 0) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(readOnly = true)
    public List<LiveInfoVo> selectOnlineLiveStreamList(Integer sceneId, Integer pushState) {
        return this.baseMapper.selectOnlineLiveStreamList(sceneId, pushState);
    }
    @Override
    @Transactional(readOnly = true)
    public List<LiveSceneLiveInfoEntity> selectLiveInfoByInfoType(Integer sceneId, Integer infoType){
        return this.baseMapper.selectLiveInfoByInfoType(sceneId,infoType);
    }
}
