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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.mts.model.v20140618.CancelJobResponse;
import com.aliyuncs.mts.model.v20140618.QueryJobListResponse;
import com.aliyuncs.mts.model.v20140618.QueryPipelineListResponse;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.aliyuncs.mts.model.v20140618.SubmitJobsResponse;
import com.platform.common.utils.DateUtils;
import com.platform.common.utils.R;
import com.platform.common.utils.ShiroUtils;
import com.platform.modules.live.constants.MediaConstants;
import com.platform.modules.live.dto.SubmitJobsDto;
import com.platform.modules.live.dto.TranscodingTaskDto;
import com.platform.modules.live.entity.LiveVideoTranscodingEntity;
import com.platform.modules.live.entity.LiveVideoTranscodingExtEntity;
import com.platform.modules.live.entity.LiveVideoTranscodingMessageEntity;
import com.platform.modules.live.service.LiveVideoTranscodingExtService;
import com.platform.modules.live.service.LiveVideoTranscodingMessageService;
import com.platform.modules.live.service.LiveVideoTranscodingService;
import com.platform.modules.live.service.TranscodingTaskService;
import com.platform.modules.live.utils.AliMediaUtils;
import com.platform.modules.live.thread.TranscodingTaskThread;
import com.platform.modules.live.utils.RSAUtils;
import com.platform.modules.oss.cloud.CloudStorageConfig;
import com.platform.modules.oss.cloud.CloudStorageService;
import com.platform.modules.oss.cloud.OSSFactory;
import com.platform.modules.sys.entity.SysUserEntity;
import com.platform.modules.sys.service.SysUserService;
import com.platform.modules.sys.service.SysUserTokenService;
import lombok.AllArgsConstructor;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @Description:
 * @Author: yikaihong
 * @CreateDate: 2019/1/28 17:44
 * @Version: 1.0
 */
@Service
@Transactional
public class TranscodingTaskServiceImpl implements TranscodingTaskService {

    @Autowired
    private LiveVideoTranscodingService liveVideoTranscodingService;
    @Autowired
    private LiveVideoTranscodingExtService liveVideoTranscodingExtService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserTokenService sysUserTokenService;
    @Autowired
    private LiveVideoTranscodingMessageService liveVideoTranscodingMessageService;

    private ExecutorService cachePool = Executors.newCachedThreadPool();

    private static final String PUB_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALERsxUILdhoJwx903Jjd2SJnFMW6wsGeKuwfezGxpTQyX20wgHtd6vOw3wCY2xyxoShdJQO1QvFF1RTSvqUj0ECAwEAAQ==";
    private static final String PRI_KEY = "MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAsRGzFQgt2GgnDH3TcmN3ZImcUxbrCwZ4q7B97MbGlNDJfbTCAe13q87DfAJjbHLGhKF0lA7VC8UXVFNK+pSPQQIDAQABAkBaYOliY9FasxazVooVydVH+MFU287OytfO8n/j2jXEAM2lK1MHD6Yc1Wk0v7ivA5bENtHJ1MSBoR5qsLYxTlDtAiEA+duVNiTq65UC33M6HZpdWItTaw6FXtgBldR9VW90ivcCIQC1bAoxaOTIjyqO0S0gzCp2L9+wVCnN8sMZksK4byoxhwIgWUPf/SYXX+8uxZIvMyBRNS8hsF/Rul7FwjfWR024f2UCIBNf+WqzcBN3Lq1X64DgLPy4OiRjqJ9E+M8HXGJEBPaLAiBq1mzd/VoHiLHYxParwV6ICbqwQayr0xveF8Lt++Sg8Q==";


    public R submit(TranscodingTaskDto dto) {
//        CloudStorageService cloudStorageService = OSSFactory.build();
//        String url = dto.getVideoUrl();
//        String fileName = UUID.randomUUID().toString().replaceAll("-", "") + url.substring(url.lastIndexOf("."));
//        String path = cloudStorageService.getPath(null, fileName);
//        try {
//            URL url1 = new URL(url);
//            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
//            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//            InputStream inputStream = conn.getInputStream();
//            String returnPath = cloudStorageService.upload(inputStream, path);
//            String ossOutputObject = UUID.randomUUID().toString().replaceAll("-", "") + "." + dto.getVideoFormat();
//            SubmitJobsDto submitJobsDto = new SubmitJobsDto(createInput(path), createOutput(ossOutputObject, dto));
//            TranscodingTaskThread thread = new TranscodingTaskThread(submitJobsDto);
//            Future future = cachePool.submit(thread);
//            SubmitJobsResponse submitJobsResponse = (SubmitJobsResponse) future.get();
//            net.sf.json.JSONObject aliReps = net.sf.json.JSONObject.fromObject(submitJobsResponse);
//            System.err.println(aliReps.toString());
//            LiveVideoTranscodingEntity entity = new LiveVideoTranscodingEntity();
//            entity.setCreateDate(new Date());
//            entity.setDelFlag("0");
//            entity.setFormatVideoUrl(ossOutputObject);
//            entity.setOperateId(ShiroUtils.getUserId()+"");
//            entity.setVideoUrl(filename);
//            entity.setRequestId(submitJobsResponse.getRequestId());
//            entity.setTaskId(submitJobsResponse.getJobResultList().get(0).getJob().getJobId());
//            entity.setTaskStatus("0");
//
//            LiveVideoTranscodingExtEntity extEntity = new LiveVideoTranscodingExtEntity();
//            extEntity.setId(entity.getId());
//            extEntity.setRequestParams(net.sf.json.JSONObject.fromObject(dto).toString());
//            extEntity.setRequestAliParams(net.sf.json.JSONObject.fromObject(submitJobsDto).toString());
//            extEntity.setResponseAliParams(net.sf.json.JSONObject.fromObject(aliReps).toString());
//            extEntity.setOperater(ShiroUtils.getUserId()+"");

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

    /**
     * 取消转码
     *
     * @param taskId
     * @return
     */
    @Override
    public R cancel(String taskId) {
        if (StringUtils.isBlank(taskId)) {
            return R.error("参数为空！");
        }

        LiveVideoTranscodingEntity entity = liveVideoTranscodingService.selectOne(new EntityWrapper<LiveVideoTranscodingEntity>().eq("task_id", taskId));
        if (entity == null) {
            return R.error("视频不存在！");
        }
//        QueryPipelineListResponse pipelineListResponse = AliMediaUtils.queryPipelineList(MediaConstants.PIPELINE_ID);
//        QueryPipelineListResponse.Pipeline pipeline = pipelineListResponse.getPipelineList().get(0);
//        net.sf.json.JSONObject pipelineObject = null;
//        if (pipeline.getNotifyConfig() != null) {
//            pipelineObject = net.sf.json.JSONObject.fromObject(pipeline.getNotifyConfig());
//        }
//
//        AliMediaUtils.updatePipeline(MediaConstants.PIPELINE_ID, pipeline.getName(), "Paused", pipelineObject == null ? null : pipelineObject.toString());
//        CancelJobResponse response = null;
//        try {
//            response = AliMediaUtils.cancelJobs(entity.getTaskId());
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//        AliMediaUtils.updatePipeline(MediaConstants.PIPELINE_ID, pipeline.getName(), "Active", pipelineObject == null ? null : pipelineObject.toString());
        entity.setDelFlag("1");//取消转码
        entity.setOperateId(ShiroUtils.getUserId().toString());
        entity.setUpdateDate(new Date());
        liveVideoTranscodingService.updateById(entity);

        //插入从表记录
        LiveVideoTranscodingExtEntity extEntity = new LiveVideoTranscodingExtEntity();
        JSONObject requestParams = new JSONObject();
        requestParams.put("taskId", taskId);
//        JSONObject requestAliParams = new JSONObject();
//        requestAliParams.put("JobId", taskId);
//        net.sf.json.JSONObject responseAliParams = net.sf.json.JSONObject.fromObject(response);
        extEntity.setId(entity.getId());
        extEntity.setRequestParams(requestParams.toJSONString());
//        extEntity.setRequestAliParams(requestAliParams.toJSONString());
//        extEntity.setResponseAliParams(responseAliParams.toString());
        extEntity.setOperater("1"); //删除
        extEntity.setCreateDate(new Date());
        liveVideoTranscodingExtService.save(extEntity);

        return R.ok();
    }

    @Override
    public R upload(MultipartFile file) {

        try {
            CloudStorageService cloudStorageService = OSSFactory.build();
            String orgFileName = file.getOriginalFilename();
            String suffix = orgFileName.substring(orgFileName.lastIndexOf("."));
            String fileName = UUID.randomUUID().toString().replaceAll("-", "");
            String dir = DateUtils.format(new Date(), "yyyyMMdd");
            String path = dir + "/src/" + fileName + suffix;
            String ossUrl = cloudStorageService.upload(file.getInputStream(), path); // 上传成功后的url
            // 提交任务
            TranscodingTaskDto dto = new TranscodingTaskDto();
            String ossOutputObject = dir + "/" + fileName + "." + dto.getVideoFormat();
            SubmitJobsResponse response = handler(dto, path, ossOutputObject);
            // 入库
            LiveVideoTranscodingEntity entity = new LiveVideoTranscodingEntity();
            entity.setCreateDate(new Date());
            entity.setDelFlag("0"); // 没有删除任务
            entity.setFormatVideoUrl(ossOutputObject);
            entity.setOperateId(ShiroUtils.getUserId() + "");
            entity.setVideoUrl(path); // oss 文件位置
            entity.setRequestId(response.getRequestId());
            entity.setTaskId(response.getJobResultList().get(0).getJob().getJobId());
            entity.setTaskStatus("0"); // 处理中
            entity.setUploadState(response.getJobResultList().get(0).getSuccess() ? "1" : "0");
            entity.setCreateDate(new Date());
            liveVideoTranscodingService.insert(entity);

            LiveVideoTranscodingExtEntity extEntity = new LiveVideoTranscodingExtEntity();
            extEntity.setId(entity.getId());
            net.sf.json.JSONObject paramJson = new net.sf.json.JSONObject();
            paramJson.put("originalFilename", file.getOriginalFilename());
            paramJson.put("contentType", file.getContentType());
            paramJson.put("name", file.getName());
            paramJson.put("size", file.getSize());
            extEntity.setRequestParams(paramJson.toString());
            extEntity.setRequestAliParams(net.sf.json.JSONObject.fromObject(dto).toString());
            extEntity.setResponseAliParams(net.sf.json.JSONObject.fromObject(response).toString());
            extEntity.setOperater(ShiroUtils.getUserId() + "");
            liveVideoTranscodingExtService.save(extEntity);
            net.sf.json.JSONObject object = net.sf.json.JSONObject.fromObject(response.getJobResultList().get(0).getJob());
            return R.ok().put("taskId", response.getJobResultList().get(0).getJob().getJobId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error();
    }


    /**
     * 获取token
     *
     * @param appKey
     * @param appSecret
     * @return
     */
    @Override
    public R token(String appKey, String appSecret) {

        try {
            // 采用base64 编码
            BASE64Decoder decoder = new BASE64Decoder();
            String userName = new String(decoder.decodeBuffer(appKey));
            //用户信息
            SysUserEntity user = sysUserService.queryByUserName(userName);
            // 对称加密
            // YWRtaW4=
            // BVHjzV7M8hCe8V56gZB/3xnF4DNfcer9bZv7MbA77ocXsjPdbkAo6Jed7s6LrPvjJZfMdLunF2rq0RVbHdH+7Q==
            String secret = new String(RSAUtils.decryptByPublicKey(Base64.decodeBase64(appSecret.getBytes()), Base64.decodeBase64(PUB_KEY)));
            //账号不存在、密码错误
            if (user == null || !user.getPassword().equals(new Sha256Hash(secret, user.getSalt()).toHex()) || user.getStatus() == 0) {
                return R.error("认证信息有误");
            }
            //生成token，并保存到数据库
            R r = sysUserTokenService.createToken(user.getUserId());
            r.put("accessToken", r.get("token"));
            r.remove("token");
            return r;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error();
    }

    @Override
    public R saveTranscodingMessage(HttpServletRequest request) {

        InputStream inputStream = null;
        LiveVideoTranscodingMessageEntity messageEntity = new LiveVideoTranscodingMessageEntity();
        //请求头信息
        messageEntity.setAuthorization(request.getHeader("Authorization"));
        messageEntity.setSigningCertUrl(request.getHeader("x-mns-signing-cert-url"));
        messageEntity.setRequestId(request.getHeader("x-mns-request-id"));
        messageEntity.setMessageId(request.getHeader("x-mns-message-id"));
        messageEntity.setMessageTag(request.getHeader("x-mns-message-tag"));
        Date currDate = new Date();
        try {
            inputStream = request.getInputStream();
            StringBuilder sb = new StringBuilder();
            byte[] b = new byte[1024];
            for (int n; (n = inputStream.read(b)) != -1; ) {
                sb.append(new String(b, 0, n));
            }

            //body信息
            JSONObject jsonObject = JSONObject.parseObject(sb.toString());
            messageEntity.setJobId(jsonObject.getString("jobId"));
            messageEntity.setType(jsonObject.getString("type"));
            messageEntity.setState(jsonObject.getString("state"));
            messageEntity.setTransRequestId(jsonObject.getString("requestId"));
            messageEntity.setCreateDate(currDate);
            liveVideoTranscodingMessageService.insert(messageEntity);

            //更新转码状态
            LiveVideoTranscodingEntity transcodingEntity = liveVideoTranscodingService.selectOne(new EntityWrapper<LiveVideoTranscodingEntity>().eq("task_id", messageEntity.getJobId()));
            if (transcodingEntity != null) {
                transcodingEntity.setTaskStatus("1");
                transcodingEntity.setUpdateDate(currDate);
                liveVideoTranscodingService.updateById(transcodingEntity);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return R.ok();
    }


    /**
     * 视频转化
     *
     * @param dto
     * @param ossInputPath
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private SubmitJobsResponse handler(TranscodingTaskDto dto, String ossInputPath, String ossOutputObject) throws ExecutionException, InterruptedException {
        SubmitJobsDto submitJobsDto = new SubmitJobsDto(createInput(ossInputPath), createOutput(ossOutputObject, dto));
        TranscodingTaskThread thread = new TranscodingTaskThread(submitJobsDto);
        Future future = cachePool.submit(thread);
//        net.sf.json.JSONObject aliReps = net.sf.json.JSONObject.fromObject(submitJobsResponse);
        return (SubmitJobsResponse) future.get();
    }

    @Override
    @Transactional(readOnly = true)
    public R query(String taskId) {
        if (StringUtils.isBlank(taskId)) {
            return R.error("参数为空！");
        }
        LiveVideoTranscodingEntity entity = liveVideoTranscodingService.selectOne(new EntityWrapper<LiveVideoTranscodingEntity>().eq("task_id", taskId));
        if (entity == null) {
            return R.error("视频不存在！");
        }

        //查询转码作业
        QueryJobListResponse response = AliMediaUtils.queryJobList(taskId);
        //插入从表记录
        LiveVideoTranscodingExtEntity extEntity = new LiveVideoTranscodingExtEntity();
        JSONObject requestParams = new JSONObject();
        requestParams.put("taskId", taskId);
        JSONObject requestAliParams = new JSONObject();
        requestAliParams.put("JobIds", taskId);
        net.sf.json.JSONObject responseAliParams = net.sf.json.JSONObject.fromObject(response);
        extEntity.setId(entity.getId());
        extEntity.setRequestParams(requestParams.toJSONString());
        extEntity.setRequestAliParams(requestAliParams.toJSONString());
        extEntity.setResponseAliParams(responseAliParams.toString());
        extEntity.setOperater("2"); //查询
        liveVideoTranscodingExtService.save(extEntity);

        return R.ok().put("response", extEntity.getResponseAliParams());
    }

    @Override
    @Transactional(readOnly = true)
    public R queryTask(String taskId) {
        if (StringUtils.isBlank(taskId)) {
            return R.error("参数为空！");
        }
        LiveVideoTranscodingEntity entity = liveVideoTranscodingService.selectOne(new EntityWrapper<LiveVideoTranscodingEntity>().eq("task_id", taskId));
        if (entity == null) {
            return R.error("视频不存在！");
        }
        String url = OSSFactory.build().getConfig().getAliyunDomain() + entity.getFormatVideoUrl();
        JSONObject jsonObject = new JSONObject();
        if ("1".equals(entity.getTaskStatus())) {
            jsonObject.put("materialUrl",url);
        }
        jsonObject.put("taskId",taskId);
        jsonObject.put("taskState",entity.getTaskStatus());
        return R.ok().put("data ",jsonObject);
    }

    /**
     * 输入
     *
     * @param ossInputObject
     * @return
     */
    private String createInput(String ossInputObject) {
        JSONObject input = new JSONObject();
        input.put("Location", MediaConstants.LOCATION);
        input.put("Bucket", MediaConstants.INPUT_BUCKET);
        try {
            input.put("Object", URLEncoder.encode(ossInputObject, "utf-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return input.toString();
    }

    /**
     * 输出
     *
     * @param ossOutputObject
     * @param dto
     * @return
     */
    private String createOutput(String ossOutputObject, TranscodingTaskDto dto) {
        String outputOSSObject;
        try {
            outputOSSObject = URLEncoder.encode(ossOutputObject, "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("output URL encode failed");
        }
        JSONObject output = new JSONObject();
        output.put("OutputObject", outputOSSObject);
        // Ouput->Container
//        JSONObject container = new JSONObject();
//        container.put("Format", dto.getVideoFormat());
//        output.put("Container", container.toJSONString());
//        // Ouput->Video
//        JSONObject video = new JSONObject();
//        video.put("Codec", dto.getVideoCodec());
//        video.put("Bitrate", dto.getVideoBitrate());
//        video.put("Width", dto.getVideoWidth());
//        video.put("Fps", dto.getVideoFps());
//        output.put("Video", video.toJSONString());
//        // Ouput->Audio
//        JSONObject audio = new JSONObject();
//        audio.put("Codec", dto.getAudioCodec());
//        audio.put("Bitrate", dto.getAudioBitrate());
//        audio.put("Channels", dto.getAudioChannels());
//        audio.put("Samplerate", dto.getAudioSamplerate());
//        output.put("Audio", audio.toJSONString());
        // Ouput->TemplateId
        output.put("TemplateId", dto.getTemplateId());
        JSONArray outputs = new JSONArray();
        outputs.add(output);
        return outputs.toJSONString();
    }

}