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

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.platform.autoconfigure.live.LiveProperties;
import com.platform.common.utils.FileUtils;
import com.platform.common.utils.HttpClientHelper;
import com.platform.common.utils.PageUtils;
import com.platform.common.utils.Query;
import com.platform.common.utils.R;
import com.platform.common.utils.RedisUtils;
import com.platform.common.utils.ShiroUtils;
import com.platform.modules.foreign.entity.SceneStreamForeignEntity;
import com.platform.modules.live.constants.LiveConstants;
import com.platform.modules.live.constants.SceneConstants;
import com.platform.modules.live.dao.LiveSceneRecordDao;
import com.platform.modules.live.entity.LiveSceneEntity;
import com.platform.modules.live.entity.LiveSceneRecordEntity;
import com.platform.modules.live.service.LiveSceneRecordService;
import com.platform.modules.live.service.LiveSceneService;
import com.platform.modules.live.utils.ForeignProperties;
import com.platform.modules.live.vo.LiveSceneRecordVo;
import com.platform.modules.oss.cloud.AliyunCloudStorageService;
import com.platform.modules.oss.cloud.CloudStorageConfig;
import com.platform.modules.plm.util.MateriaFileProperties;
import com.platform.modules.plm.util.MaterialUtils;
import com.platform.modules.video.service.RealPathResolver;
import com.platform.plugs.live.LiveClient;


@Service("liveSceneRecordService")
@Transactional
public class LiveSceneRecordServiceImpl extends ServiceImpl<LiveSceneRecordDao, LiveSceneRecordEntity> implements LiveSceneRecordService {

    @Autowired
    private MateriaFileProperties materiaFileProperties;
    @Autowired
    private RealPathResolver realPathResolver;
    @Autowired
    private LiveProperties properties;
    @Autowired
    private LiveSceneService liveSceneService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private ForeignProperties foreignProperties;
    @Autowired
    private LiveClient liveClient;

    @Override
    @Transactional(readOnly = true)
    public PageUtils queryPage(Map<String, Object> params) {
        EntityWrapper<LiveSceneRecordEntity> wrapper = new EntityWrapper<>();
        String recordName = (String) params.get("recordName"); //回顾名称
        String status = (String)params.get("recordStatus"); //状态
        String sceneId = (String)params.get("sceneId"); //现场ID
        if (StringUtils.isNotBlank(recordName)) {
            wrapper.like("record_name", recordName);
        }
        if (StringUtils.isNotBlank(status)) {
            wrapper.eq("record_status", Integer.parseInt(status));
        }
        if (StringUtils.isNotBlank(sceneId)) {
            wrapper.eq("scene_id", Integer.parseInt(sceneId));
        }
        wrapper.eq("is_delete", SceneConstants.NOT_DELETE);
        wrapper.gt("duration",10);
        wrapper.orderBy("priority", false);
        wrapper.orderBy("id", false);
        // 20200306_Mxy 不显示m3u8类型的回顾
        wrapper.ne("record_type", LiveConstants.RecordType.M3U8_RECORD);
        Page<LiveSceneRecordEntity> page = this.selectPage(
                new Query<LiveSceneRecordEntity>(params).getPage(),
                wrapper
        );

        Page<LiveSceneRecordVo> resultPage = new Page<>();
        if (page != null && page.getRecords() != null && page.getRecords().size() > 0) {

            resultPage.setTotal(page.getTotal());
            resultPage.setSize(page.getSize());
            resultPage.setCurrent(page.getCurrent());

            List<LiveSceneRecordVo> list = new ArrayList<>();
            LiveSceneRecordVo recordVo = null;
            for (LiveSceneRecordEntity entity : page.getRecords()) {
                try {
                    recordVo = new LiveSceneRecordVo(entity);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                // 20200316_Mxy 图片压缩
                recordVo.setTitleImageShow(MaterialUtils.getMaterialUrl(compressImage(entity.getTitleImage()), foreignProperties.getMediaurl()));
                // recordVo.setTitleImageShow(MaterialUtils.getMaterialUrl(entity.getTitleImage(), foreignProperties.getMediaurl()));
                recordVo.setUriShow(MaterialUtils.getMaterialUrl(entity.getUri(), foreignProperties.getMediaurl()));
                list.add(recordVo);
            }
            resultPage.setRecords(list);

        }

        return new PageUtils(resultPage);
    }
    
    @Override
    @Transactional(readOnly = true)
    public LiveSceneRecordVo info(Integer id){
    	LiveSceneRecordEntity entity = this.selectById(id);
    	LiveSceneRecordVo recordVo = null;
		try {
			recordVo = new LiveSceneRecordVo(entity);
            // 20200316_Mxy 图片压缩
			recordVo.setTitleImageShow(MaterialUtils.getMaterialUrl(compressImage(entity.getTitleImage()), foreignProperties.getMediaurl()));
            // recordVo.setTitleImageShow(MaterialUtils.getMaterialUrl(entity.getTitleImage(), foreignProperties.getMediaurl()));
			recordVo.setUriShow(MaterialUtils.getMaterialUrl(entity.getUri(), foreignProperties.getMediaurl()));
		} catch (ParseException e) {
			e.printStackTrace();
		}
    	return recordVo;
    }

    /**
     * 获取对外回顾视频信息
     * @param sceneId 现场ID
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public List<SceneStreamForeignEntity> selectSceneRecordForeign(Integer sceneId) {
        List<SceneStreamForeignEntity> rtList = new ArrayList<>();
        EntityWrapper<LiveSceneRecordEntity> ew = new EntityWrapper<>();
        ew.eq("scene_id", sceneId);
        ew.eq("record_status", SceneConstants.RECORD_SHOW);
        ew.eq("is_delete", SceneConstants.NOT_DELETE);
        ew.orderBy("priority", false);
        List<LiveSceneRecordEntity> recordList = this.selectList(ew);
        if (null!=recordList && recordList.size()>0) {
            for (LiveSceneRecordEntity record : recordList) {
                rtList.add(new SceneStreamForeignEntity(record, foreignProperties.getMediaurl()));
            }
        }
        return rtList;
    }

    @Override
    public void deleteRecords(Integer[] ids) {
        List<LiveSceneRecordEntity> list = new ArrayList<>();
        // 20190304 TROY 删除回顾视频影响回顾现场详情
        Map<Integer, Integer> sceneMap = new HashMap<>(ids.length);
        for (Integer id : ids) {
            LiveSceneRecordEntity entity = selectById(id);
            if (entity != null) {
                entity.setIsDelete(SceneConstants.IS_DELETE);
                list.add(entity);

                if (Integer.valueOf(SceneConstants.RECORD_SHOW).equals(entity.getRecordStatus()) &&
                        !sceneMap.containsKey(entity.getSceneId())) {
                    sceneMap.put(entity.getSceneId(), entity.getSceneId());
                }
            }
        }
        updateBatchById(list);

        for (Integer sid : sceneMap.keySet()) {
            redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + sid);
        }
    }

    @Override
    public void update(LiveSceneRecordVo liveSceneRecordVo) {

        LiveSceneRecordEntity recordEntity = selectById(liveSceneRecordVo.getId());
        if (recordEntity == null || liveSceneRecordVo.getSceneId() == null) {
            throw new NullPointerException();
        }
        LiveSceneRecordEntity entity = new LiveSceneRecordEntity(liveSceneRecordVo);
        LiveSceneEntity sceneEntity = liveSceneService.selectById(entity.getSceneId());
        if (sceneEntity == null) {
            throw new NullPointerException();
        }
        entity.setLastUpdateDate(new Date());
        entity.setLastUpdatorId(ShiroUtils.getUserId().intValue());
        // 保存标题图 20190320Anine:使用素材路径保存titleImage
        entity.setTitleImage(liveSceneRecordVo.getTitleImage());
//        entity.setTitleImage(saveFile(materialFile));
//        if (uploadVideoName != null) {
//            //上传视频至oss
//            String uri = uploadVideo(sceneEntity.getSceneSign(), uploadVideoName);
//            entity.setUri(uri);
//        }

        updateById(entity);

        // 20190304 TROY 回顾视频状态更新需要更新回顾现场信息
        // 20190329 TROY 显示的回顾需要更新现场信息
        boolean refresh = null!=liveSceneRecordVo.getRecordStatus() &&
                SceneConstants.LIVE_STATE_REVIEW.equals(sceneEntity.getSceneState()) &&
                (Integer.valueOf(SceneConstants.RECORD_SHOW).equals(entity.getRecordStatus()) ||
                        !recordEntity.getRecordStatus().equals(liveSceneRecordVo.getRecordStatus()));
        if (refresh) {
            redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + recordEntity.getSceneId());
        }
        // END
    }

    @Override
    public void save(LiveSceneRecordVo liveSceneRecordVo) {
        LiveSceneRecordEntity entity = new LiveSceneRecordEntity(liveSceneRecordVo);
        if (entity.getSceneId() == null) {
            throw new NullPointerException();
        }
        LiveSceneEntity sceneEntity = liveSceneService.selectById(entity.getSceneId());
        if (sceneEntity == null) {
            throw new NullPointerException();
        }
        entity.setCreateDate(new Date());
        entity.setCreatorId(ShiroUtils.getUserId().intValue());
        // 保存标题图 20190320Anine:使用素材路径保存titleImage
        entity.setTitleImage(liveSceneRecordVo.getTitleImage());
//        if (uploadPicName == null)
//            entity.setTitleImage(sceneEntity.getTitleImage());
//        else
//            entity.setTitleImage(saveFile(uploadPicName));
        // 20190304 TROY 前端传值判断
        if (null != liveSceneRecordVo.getRecordStatus()) {
            entity.setRecordStatus(liveSceneRecordVo.getRecordStatus());
        } else {
            entity.setRecordStatus(SceneConstants.RECORD_TO_SHOW);
        }
        // end
        entity.setIsDelete(SceneConstants.NOT_DELETE);
        //上传视频至oss
//        String uri = uploadVideo(sceneEntity.getSceneSign(), uploadVideoName);
//        entity.setUri(uri);
        this.baseMapper.insert(entity);

        // 20190304 TROY 回顾现场创建发布回顾视频
        if (SceneConstants.LIVE_STATE_REVIEW.equals(sceneEntity.getSceneState()) &&
                Integer.valueOf(SceneConstants.RECORD_SHOW).equals(liveSceneRecordVo.getRecordStatus())) {
            redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + sceneEntity.getId());
        }
        // END
    }
    
    @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){
				LiveSceneRecordEntity entity = new LiveSceneRecordEntity();
				entity.setPriority(prioritys[i]);
				entity.setLastUpdateDate(new Date());
				entity.setLastUpdatorId(ShiroUtils.getUserId().intValue());;
				entity.setId(ids[i]);
				this.baseMapper.updateById(entity);
			}
		}
    }

    @Override
    public R fastClip(Integer recordId, Integer clipStartTime, Integer clipStopTime, String recordName) {

        // 根据id获取回顾
        LiveSceneRecordEntity recordEntity = this.selectById(recordId);

        if (null == recordEntity)
            return R.error("获取回顾信息失败");

        if (!LiveConstants.RecordType.FAST_RECORD.equals(recordEntity.getRecordType()))
            return R.error("只有快速回看视频可以进行快速剪辑");

        if ((null != clipStartTime && clipStartTime > recordEntity.getStopTime())
                || (null != clipStopTime && clipStopTime > recordEntity.getStopTime())
                || (null != clipStartTime && null != clipStopTime && clipStartTime >= clipStopTime))
            return R.error("参数错误");

        // 剪辑开始与结束时间
        Long start = (long)(null == clipStartTime ? 0 : clipStartTime + 1);
        Long stop = (long)(null == clipStopTime ? recordEntity.getStopTime() : clipStopTime);
        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        Date startTime = new Date(start * 1000);
        Date stopTime = new Date(stop * 1000);

        // 生成快速剪辑回顾
        LiveSceneRecordEntity clipRecordEntity = new LiveSceneRecordEntity();

        clipRecordEntity.setRecordType(LiveConstants.RecordType.CLIP_RECORD);
        clipRecordEntity.setSceneId(recordEntity.getSceneId());
        clipRecordEntity.setDuration((double)(stop - start));
        clipRecordEntity.setStartTime(clipStartTime);
        clipRecordEntity.setStopTime(clipStopTime);
        clipRecordEntity.setCreateDate(new Date());
        clipRecordEntity.setRecordStatus(SceneConstants.RECORD_TO_SHOW);
        clipRecordEntity.setIsDelete(SceneConstants.NOT_DELETE);
        clipRecordEntity.setTenantId(recordEntity.getTenantId());
        clipRecordEntity.setRecordName(recordName);
        if (null != recordEntity.getCreatorId())
            clipRecordEntity.setCreatorId(recordEntity.getCreatorId());
        if (StringUtils.isNotBlank(recordEntity.getTitleImage()))
            clipRecordEntity.setTitleImage(recordEntity.getTitleImage());
        // 设置Uri
        String uri = recordEntity.getUri().substring(0, recordEntity.getUri().indexOf("&"));
        String clipUri = uri + String.format("&aliyunols=on&lhs_start_human_s_8=%s&lhs_end_human_s_8=%s", df.format(startTime), df.format(stopTime));
        clipRecordEntity.setUri(clipUri);

        this.insert(clipRecordEntity);

        return R.ok();
    }

    @Override
    public R getTimeLine(Integer recordId) {

        // 获取回顾信息
        LiveSceneRecordEntity recordEntity = this.selectById(recordId);

        if (null == recordEntity || StringUtils.isBlank(recordEntity.getUri())
                || null == recordEntity.getStartTime() || null == recordEntity.getStopTime())
            return R.error("获取回顾信息错误");

        // 获取app名称与流名称
        String url = StringUtils.substringBefore(StringUtils.substringAfter(recordEntity.getUri(), properties.getDomains().getLive().getDomainName() + "/"), ".m3u8");
        String app = StringUtils.substringBefore(url, "/");
        String stream = StringUtils.substringAfter(url, "/");

        // 拼接请求地址
        String requestUrl = liveClient.liveStream().generateQueryTimeLineUrl(recordEntity.getStartTime(), recordEntity.getStopTime(), app, stream);
        String result = HttpClientHelper.sendGet(requestUrl, null, "UTF-8",false);
        // 获取结果
        JSONObject json = JSON.parseObject(result);

        if (!"0".equals(json.get("retCode")) && !"success".equals(json.get("description")))
            return R.error("请求失败");

        return R.ok().put("result", json);
    }
    /**
     * 获取m3u8文件的切片时长
     * @param recordId
     * @return
     */
    @Override
    public R getSlicingTime(Integer recordId){
    	// 获取回顾信息
        LiveSceneRecordEntity recordEntity = this.selectById(recordId);

        if (null == recordEntity || StringUtils.isBlank(recordEntity.getUri())
                || null == recordEntity.getStartTime() || null == recordEntity.getStopTime())
            return R.error("获取回顾信息错误");
        Integer[] times = null;
        
        String content = HttpClientHelper.sendGetAndGetFileContent(MaterialUtils.getMaterialUrl(recordEntity.getUri(), foreignProperties.getMediaurl()), false);
        
        if(StringUtils.isNotBlank(content)){
        	String[] strs = content.replaceAll("(#EXT).*[\n]", "").split("\n");
        	if(strs!=null && strs.length>0){
        		times = new Integer[strs.length+1];
                times[0] = recordEntity.getStartTime();
        		for(int i=0;i<strs.length;i++){
        			String str = strs[i];
        			if(StringUtils.isNotBlank(str)){
        				str = StringUtils.substringAfter(str, "/");
        				str = StringUtils.substringBefore(str, "_");
        				times[i+1] = StringUtils.isNotBlank(str) ? Integer.valueOf(str) : null;
        			}
        		}
        	}
        }
        
        return R.ok().put("slicingTimes", times);
    }

    private String uploadVideo(String appName, MultipartFile file) throws IOException {
        if (file == null) {
            return null;
        }
        CloudStorageConfig cloudStorageConfig = new CloudStorageConfig();
        cloudStorageConfig.setAliyunAccessKeyId(properties.getAccount().getAccessKeyId());
        cloudStorageConfig.setAliyunAccessKeySecret(properties.getAccount().getSecret());
        cloudStorageConfig.setAliyunBucketName(properties.getRecord().getOssBucket());
        // 20190308 TROY 数据库路径取消域名赋值
//        cloudStorageConfig.setAliyunDomain(properties.getRecord().getDomainName());
        cloudStorageConfig.setAliyunDomain("");
        cloudStorageConfig.setAliyunEndPoint(properties.getRecord().getOssEndpoint());
        AliyunCloudStorageService aliyunCloudStorageService = new AliyunCloudStorageService(cloudStorageConfig);
        String orgFileName = file.getOriginalFilename();
        String suffix = orgFileName.substring(orgFileName.lastIndexOf("."));
        String fileName = UUID.randomUUID().toString().replaceAll("-", "");
        String prefix = properties.getRecord().getRecordFormat().getOssRecordPrefix();
        if(!prefix.endsWith("/")) prefix += "/";
        String path = prefix + appName +"/" + fileName + suffix;
        String ossUrl = aliyunCloudStorageService.upload(file.getInputStream(), path); // 上传成功后的url
        return ossUrl;
    }

    private String saveFile(MultipartFile material) {
        String serverMaterialPath = null;
        if(material != null && !material.isEmpty()){
            String newMaterialName = FileUtils.createFileName() + "." + FileUtils.getSuffix(material.getOriginalFilename());
            serverMaterialPath = materiaFileProperties.getMediaPath() + "/" + MaterialUtils.getDateDir() + "/" + newMaterialName;
            String newMaterialPath = realPathResolver.get(materiaFileProperties.getMateriaPath() + serverMaterialPath);
            try {
                FileUtils.copy(material.getInputStream(), newMaterialPath);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return serverMaterialPath;
    }

    /**
     * 20200316_Mxy 图片压缩
     *
     * @param sourceUrl 图片地址
     * */
    private String compressImage(String sourceUrl){
        // 返回拼接压缩后地址
        return sourceUrl + properties.getCompressImage().getGeometricFormat();
    }
}
