package com.zhongzheng.modules.polyv.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhongzheng.common.core.redis.RedisCache;
import com.zhongzheng.common.utils.DateUtils;
import com.zhongzheng.common.utils.http.HttpUtils;
import com.zhongzheng.common.utils.polyv.PolyvUtils;
import com.zhongzheng.modules.polyv.domain.PolyvVideDo;
import com.zhongzheng.modules.polyv.vo.PolyvVideoQuerVo;
import com.zhongzheng.modules.polyv.domain.TokenResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.zhongzheng.modules.polyv.bo.PolyvVideoAddBo;
import com.zhongzheng.modules.polyv.bo.PolyvVideoQueryBo;
import com.zhongzheng.modules.polyv.bo.PolyvVideoEditBo;
import com.zhongzheng.modules.polyv.domain.PolyvVideo;
import com.zhongzheng.modules.polyv.mapper.PolyvVideoMapper;
import com.zhongzheng.modules.polyv.vo.PolyvVideoVo;
import com.zhongzheng.modules.polyv.service.IPolyvVideoService;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.squareup.okhttp.internal.Util.md5Hex;

/**
 * 保利威视频信息Service业务层处理
 *
 * @author change
 * @date 2021-06-11
 */
@Service
public class PolyvVideoServiceImpl extends ServiceImpl<PolyvVideoMapper, PolyvVideo> implements IPolyvVideoService {

    @Value("${poliv.token.userid}")
    private String poliv_token_userid;

    @Value("${poliv.token.writetoken}")
    private String poliv_token_writetoken;

    @Value("${poliv.token.readtoken}")
    private String poliv_token_readtoken;

    @Value("${poliv.token.secretkey}")
    private String poliv_token_secretkey;

    @Autowired
    private RedisCache redisCache;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PolyvVideoQuerVo queryById(String VId) throws Exception {
        PolyvVideo polyvVideo = baseMapper.selectByVID(VId);
        //找不到发送请求获得视频，并加入数据库
        if (polyvVideo == null){
            polyvbRequest(VId);
            polyvVideo = baseMapper.selectByVID(VId);
        }
        PolyvVideoQuerVo polyvVideoQuerVo = VoTOQueryVo(polyvVideo);
        return polyvVideoQuerVo;
    }

    private PolyvVideoQuerVo VoTOQueryVo(PolyvVideo polyvVideo) {
        PolyvVideoQuerVo polyvVideoQuerVo = BeanUtil.toBean(polyvVideo, PolyvVideoQuerVo.class);
        polyvVideoQuerVo.setImagesB(JSONArray.parseArray(polyvVideo.getImagesB(), String.class));
        polyvVideoQuerVo.setImages(JSONArray.parseArray(polyvVideo.getImages(), String.class));
        polyvVideoQuerVo.setImageUrls(JSONArray.parseArray(polyvVideo.getImageUrls(), String.class));
        polyvVideoQuerVo.setFileSize(JSONArray.parseArray(polyvVideo.getFileSize(), String.class));
        polyvVideoQuerVo.setHls(JSONArray.parseArray(polyvVideo.getHls(), String.class));
        return polyvVideoQuerVo;
    }

    /**
     * PC播放加密视频
     * @param VId
     * @return
     * @throws Exception
     */
    @Override
    public String polyvbPcSignRequest(String VId,String viewerId) throws Exception {
        viewerId = "ADMIN_"+ viewerId;
        String redsKey = "PL_VIDEO_"+viewerId+VId;
        String token = redisCache.getCacheObject(redsKey);
        if(token!=null){
            return token;
        }
        String secretKey = poliv_token_secretkey;
        String userId = poliv_token_userid;
        //业务参数
        String url = "http://hls.videocc.net/service/v1/token";
        String videoId = VId;
        String ts = Long.toString(System.currentTimeMillis());
        int expireTime = 30;//分钟
        String disposable = "false"; //true：token仅一次有效
        String iswxa = "0"; //是否微信小程序播放

        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("userId", userId);
        requestMap.put("videoId", videoId);
        requestMap.put("ts", ts);
        requestMap.put("viewerId", viewerId);
        requestMap.put("expires", String.valueOf((expireTime*60))); //令牌有效期半小时
        requestMap.put("disposable", disposable);
        requestMap.put("iswxa", iswxa);

        //用md5进行签名
        requestMap.put("sign", PolyvUtils.getSignMd5(requestMap, secretKey));

        String response = HttpUtils.postFormBody(url, requestMap);
        try {
            //解析json
            ObjectMapper objectMapper = new ObjectMapper();
            TokenResponse tokenResponse = objectMapper.readValue(response, TokenResponse.class);
            // 响应代码，200为成功，403为ts过期或签名错误，400为参数错误（例如缺少 userId 或 videoId）
            if (tokenResponse.getCode() == 200) {
                Map data = (Map) tokenResponse.getData();
                token = data.get("token").toString();
                redisCache.setCacheObject(redsKey, token, expireTime, TimeUnit.MINUTES);
                return token;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Map<String,Object> polyvbMobileSignRequest(String VId, String viewerId) throws Exception {
        viewerId = "MOBILE_"+ viewerId;
        String redsKey = "PL_VIDEO_"+viewerId+VId;
/*        String token = redisCache.getCacheObject(redsKey);
        if(token!=null){
            return token;
        }*/
        String secretkey = poliv_token_secretkey;
        String userId = poliv_token_userid;
        String videoId = VId;  // 视频vid
        long ts = System.currentTimeMillis();      // 时间戳
        String extraParams = "HTML5";  // 自定义扩展参数
        boolean disposable = false; // true 表示 token 仅一次有效。false 则表示在有效期内可以多次验证。默认为 false。
        String iswxa = "1";
        /* 将参数 userId、secretkey、videoId、ts、viewerIp、viewerIp、viewerId、viewerName、extraParams按照ASCKII升序 key + value + key + value ... +value 拼接
         */
        String concated = "extraParams" + extraParams  + "ts" + ts + "userId" + userId + "videoId" + videoId + "viewerId" + viewerId  ;
        // 首尾加上secretkey值
        String plain = secretkey + concated + secretkey;
        // 取大写MD5，可自行选择md5库
        String sign = md5Hex(plain).toUpperCase();

        Map<String,Object> map = new HashMap<>();
        map.put("sign",sign);
        map.put("ts",ts);
        return map;

    /*    String url = "https://hls.videocc.net/service/v1/token";


        Map<String, String> params = new HashMap<>();
        params.put("userId", userId);
        params.put("videoId", videoId);
        params.put("ts", String.valueOf(ts));
        params.put("extraParams", extraParams);
        params.put("viewerId", viewerId);
        params.put("sign", sign);
        params.put("iswxa", iswxa);

        // 可自行选择http客户端
        String response = HttpUtils.postFormBody(url, params);

        try {
            //解析json
            ObjectMapper objectMapper = new ObjectMapper();
            TokenResponse tokenResponse = objectMapper.readValue(response, TokenResponse.class);
            // 响应代码，200为成功，403为ts过期或签名错误，400为参数错误（例如缺少 userId 或 videoId）
            if (tokenResponse.getCode() == 200) {
                Map data = (Map) tokenResponse.getData();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;*/
    }


    public void polyvbRequest(String VId) throws Exception {
        //获得保利威sign
        Long ptime = System.currentTimeMillis();
        Map<String,String> map = new HashMap<>();
        map.put("vid",VId);
        map.put("ptime",ptime.toString());
        String sign = PolyvUtils.getSign(map, poliv_token_secretkey);

        //发送请求
        String param = "vid="+VId+"&ptime="+ptime+"&sign="+sign;
        String polyvVide = HttpUtils.sendGet("http://api.polyv.net/v2/video/" + poliv_token_userid + "/get-video-msg", param);
        JSONObject jsonObject = JSONObject.parseObject(polyvVide);
        //非200抛出异常
        if (HttpStatus.HTTP_OK != Convert.toInt(jsonObject.get("code"))){
            throw new RuntimeException(Convert.toStr(jsonObject.get("message")));
        }

        //将数据存于数据库
        JSONArray jsonArray=jsonObject.getJSONArray("data");
        List<PolyvVideDo> ist=jsonArray.toJavaList(PolyvVideDo.class);
        ist.stream().forEach(i -> {
            PolyvVideo polyvVideo = BeanUtil.toBean(i, PolyvVideo.class);
            polyvVideo.setUploaderEmail(i.getUploader().getEmail());
            polyvVideo.setUploaderName(i.getUploader().getName());
            polyvVideo.setUploaderRole(i.getUploader().getRole());
            polyvVideo.setCreateTime(DateUtils.getNowTime());
            polyvVideo.setUpdateTime(DateUtils.getNowTime());
            this.save(polyvVideo);
        });
    }
    @Override
    public List<PolyvVideoVo> queryList(PolyvVideoQueryBo bo) {
        LambdaQueryWrapper<PolyvVideo> lqw = Wrappers.lambdaQuery();
        lqw.eq(StrUtil.isNotBlank(bo.getVid()), PolyvVideo::getVid, bo.getVid());
        lqw.eq(StrUtil.isNotBlank(bo.getTag()), PolyvVideo::getTag, bo.getTag());
        lqw.eq(StrUtil.isNotBlank(bo.getMp4()), PolyvVideo::getMp4, bo.getMp4());
        lqw.eq(bo.getPlayerWidth() != null, PolyvVideo::getPlayerWidth, bo.getPlayerWidth());
        lqw.eq(StrUtil.isNotBlank(bo.getTitle()), PolyvVideo::getTitle, bo.getTitle());
        lqw.eq(bo.getDf() != null, PolyvVideo::getDf, bo.getDf());
        lqw.eq(StrUtil.isNotBlank(bo.getTimes()), PolyvVideo::getTimes, bo.getTimes());
        lqw.eq(StrUtil.isNotBlank(bo.getMp4_1()), PolyvVideo::getMp4_1, bo.getMp4_1());
        lqw.eq(StrUtil.isNotBlank(bo.getMp4_2()), PolyvVideo::getMp4_2, bo.getMp4_2());
        lqw.eq(bo.getCataid() != null, PolyvVideo::getCataid, bo.getCataid());
        lqw.eq(StrUtil.isNotBlank(bo.getMp4_3()), PolyvVideo::getMap4_3, bo.getMp4_3());
        lqw.eq(StrUtil.isNotBlank(bo.getSwfLink()), PolyvVideo::getSwfLink, bo.getSwfLink());
        lqw.eq(StrUtil.isNotBlank(bo.getStatus()), PolyvVideo::getStatus, bo.getStatus());
        lqw.eq(bo.getSeed() != null, PolyvVideo::getSeed, bo.getSeed());
        lqw.eq(StrUtil.isNotBlank(bo.getFlv1()), PolyvVideo::getFlv1, bo.getFlv1());
        lqw.eq(StrUtil.isNotBlank(bo.getFlv2()), PolyvVideo::getFlv2, bo.getFlv2());
        lqw.eq(StrUtil.isNotBlank(bo.getFlv3()), PolyvVideo::getFlv3, bo.getFlv3());
        lqw.eq(StrUtil.isNotBlank(bo.getSourceFile()), PolyvVideo::getSourceFile, bo.getSourceFile());
        lqw.eq(StrUtil.isNotBlank(bo.getDuration()), PolyvVideo::getDuration, bo.getDuration());
        lqw.eq(StrUtil.isNotBlank(bo.getFirstImage()), PolyvVideo::getFirstImage, bo.getFirstImage());
        lqw.eq(StrUtil.isNotBlank(bo.getOriginalDefinition()), PolyvVideo::getOriginalDefinition, bo.getOriginalDefinition());
        lqw.eq(StrUtil.isNotBlank(bo.getContext()), PolyvVideo::getContext, bo.getContext());
        lqw.eq(StrUtil.isNotBlank(bo.getPlayerheight()), PolyvVideo::getPlayerheight, bo.getPlayerheight());
        lqw.eq(bo.getPtime() != null, PolyvVideo::getPtime, bo.getPtime());
        lqw.eq(StrUtil.isNotBlank(bo.getSourceFilesize()), PolyvVideo::getSourceFilesize, bo.getSourceFilesize());
        lqw.eq(StrUtil.isNotBlank(bo.getMd5checksum()), PolyvVideo::getMd5checksum, bo.getMd5checksum());
        lqw.eq(bo.getTsfilesize1() != null, PolyvVideo::getTsfilesize1, bo.getTsfilesize1());
        lqw.eq(bo.getTsfilesize2() != null, PolyvVideo::getTsfilesize2, bo.getTsfilesize2());
        lqw.eq(bo.getTsfilesize3() != null, PolyvVideo::getTsfilesize3, bo.getTsfilesize3());
        lqw.eq(StrUtil.isNotBlank(bo.getPreviewVid()), PolyvVideo::getPreviewVid, bo.getPreviewVid());
        lqw.eq(StrUtil.isNotBlank(bo.getKeepsource()), PolyvVideo::getKeepsource, bo.getKeepsource());
        lqw.like(StrUtil.isNotBlank(bo.getCataName()), PolyvVideo::getCataName, bo.getCataName());
        lqw.eq(StrUtil.isNotBlank(bo.getDefaultVideo()), PolyvVideo::getDefaultVideo, bo.getDefaultVideo());
        lqw.eq(StrUtil.isNotBlank(bo.getUploaderEmail()), PolyvVideo::getUploaderEmail, bo.getUploaderEmail());
        lqw.like(StrUtil.isNotBlank(bo.getUploaderName()), PolyvVideo::getUploaderName, bo.getUploaderName());
        lqw.eq(StrUtil.isNotBlank(bo.getUploaderRole()), PolyvVideo::getUploaderRole, bo.getUploaderRole());
        lqw.eq(StrUtil.isNotBlank(bo.getHlsLevel()), PolyvVideo::getHlsLevel, bo.getHlsLevel());
        lqw.eq(StrUtil.isNotBlank(bo.getImagesB()), PolyvVideo::getImagesB, bo.getImagesB());
        lqw.eq(StrUtil.isNotBlank(bo.getImages()), PolyvVideo::getImages, bo.getImages());
        lqw.eq(StrUtil.isNotBlank(bo.getImageUrls()), PolyvVideo::getImageUrls, bo.getImageUrls());
        lqw.eq(StrUtil.isNotBlank(bo.getFileSize()), PolyvVideo::getFileSize, bo.getFileSize());
        lqw.eq(StrUtil.isNotBlank(bo.getHls()), PolyvVideo::getHls, bo.getHls());
        return entity2Vo(this.list(lqw));
    }

    /**
    * 实体类转化成视图对象
    *
    * @param collection 实体类集合
    * @return
    */
    private List<PolyvVideoVo> entity2Vo(Collection<PolyvVideo> collection) {
        List<PolyvVideoVo> voList = collection.stream()
                .map(any -> BeanUtil.toBean(any, PolyvVideoVo.class))
                .collect(Collectors.toList());
        if (collection instanceof Page) {
            Page<PolyvVideo> page = (Page<PolyvVideo>)collection;
            Page<PolyvVideoVo> pageVo = new Page<>();
            BeanUtil.copyProperties(page,pageVo);
            pageVo.addAll(voList);
            voList = pageVo;
        }
        return voList;
    }

    @Override
    public Boolean insertByAddBo(PolyvVideoAddBo bo) {
        PolyvVideo add = BeanUtil.toBean(bo, PolyvVideo.class);
        validEntityBeforeSave(add);
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        return this.save(add);
    }

    @Override
    public Boolean updateByEditBo(PolyvVideoEditBo bo) {
        PolyvVideo update = BeanUtil.toBean(bo, PolyvVideo.class);
        validEntityBeforeSave(update);
        update.setUpdateTime(DateUtils.getNowTime());
        return this.updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(PolyvVideo entity){
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return this.removeByIds(ids);
    }


}
