import oss2
import time
from voduploadsdk.AliyunVodUtils import *
from exception.CustomerException import ServiceException
from enums.ExceptionEnum import ExceptionType
import json
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from voduploadsdk.AliyunVodUtils import *
from voduploadsdk.AliyunVodUploader import AliyunVodUploader
from voduploadsdk.UploadVideoRequest import UploadVideoRequest


class AliyunOssSdk():

    def __init__(self, content, logger, requestId):
        self.content = content
        self.bucket = None
        self.logger = logger
        self.requestId = requestId

    def get_oss_bucket(self):
        if self.bucket is None:
            self.logger.info("初始化oss桶, requestId:{}", self.requestId)
            auth = oss2.Auth(self.content["aliyun"]["access_key"], self.content["aliyun"]["access_secret"])
            self.bucket = oss2.Bucket(auth, self.content["aliyun"]["oss"]["endpoint"],
                                      self.content["aliyun"]["oss"]["bucket"],
                                      connect_timeout=self.content["aliyun"]["oss"]["connect_timeout"])

    def upload_file(self, updatePath, fileByte):
        self.logger.info("开始上传文件到oss, requestId:{}", self.requestId)
        self.get_oss_bucket()
        MAX_RETRIES = 3
        retry_count = 0
        while True:
            try:
                self.bucket.put_object(updatePath, fileByte)
                self.logger.info("上传文件到oss成功! requestId:{}", self.requestId)
                break
            except Exception as e:
                retry_count += 1
                time.sleep(1)
                self.logger.info("上传文件到oss失败, 重试次数：{}, requestId:{}", retry_count, self.requestId)
                if retry_count > MAX_RETRIES:
                    self.logger.exception("上传文件到oss重试失败:{}, requestId:{}", e, self.requestId)
                    raise e


class ThAliyunVodSdk():

    def __init__(self, content, logger, requestId):
        self.content = content
        self.logger = logger
        self.requestId = requestId

    def init_vod_client(self, accessKeyId, accessKeySecret):
        regionId = self.content["aliyun"]["vod"]["ecsRegionId"]
        return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=5)

    def get_play_info(self, videoId):
        self.logger.info("开始获取视频地址，videoId:{}, requestId:{}", videoId, self.requestId)
        start = time.time()
        while True:
            try:
                clt = self.init_vod_client(self.content["aliyun"]["access_key"],
                                           self.content["aliyun"]["access_secret"])
                request = GetPlayInfoRequest.GetPlayInfoRequest()
                request.set_accept_format('JSON')
                request.set_VideoId(videoId)
                request.set_AuthTimeout(3600 * 5)
                response = json.loads(clt.do_action_with_exception(request))
                play_url = response["PlayInfoList"]["PlayInfo"][0]["PlayURL"]
                self.logger.info("获取视频地址成功，视频地址: {}, requestId: {}", play_url, self.requestId)
                return play_url
            except Exception as e:
                self.logger.error("获取视频地址失败，5秒后重试, requestId: {}", self.requestId)
                time.sleep(5)
                current_time = time.time()
                if "HTTP Status: 403" not in str(e):
                    self.logger.exception("获取视频地址失败: {}, requestId: {}", e, self.requestId)
                    raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
                                           ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
                if "HTTP Status: 403" in str(e) and ("UploadFail" in str(e) or "TranscodeFail" in str(e)):
                    self.logger.exception("获取视频地址失败: {}, requestId: {}", e, self.requestId)
                    raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
                                           ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
                diff_time = current_time - start
                if diff_time > 60 * 60 * 2:
                    self.logger.exception("获取视频地址失败超时异常: {}，超时时间：{}, requestId: {}", e, diff_time, self.requestId)
                    raise ServiceException(ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[0],
                                           ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[1])

    def upload_local_video(self, filePath, file_title, storageLocation=None):
        self.logger.info("开始执行vod视频上传, filePath: {}, requestId: {}", filePath, self.requestId)
        uploader = AliyunVodUploader(self.content["aliyun"]["access_key"], self.content["aliyun"]["access_secret"])
        uploadVideoRequest = UploadVideoRequest(filePath, file_title)
        # 可以设置视频封面，如果是本地或网络图片可使用UploadImageRequest上传图片到视频点播，获取到ImageURL
        # ImageURL示例：https://example.com/sample-****.jpg
        # uploadVideoRequest.setCoverURL('<your Image URL>')
        # 标签
        # uploadVideoRequest.setTags('tag1,tag2')
        if storageLocation:
            uploadVideoRequest.setStorageLocation(storageLocation)
        MAX_RETRIES = 3
        retry_count = 0
        while True:
            try:
                result = uploader.uploadLocalVideo(uploadVideoRequest)
                self.logger.info("vod视频上传成功, videoId:{}, requestId:{}", result.get("VideoId"), self.requestId)
                return result.get("VideoId")
            except AliyunVodException as e:
                retry_count += 1
                time.sleep(3)
                self.logger.error("vod视频上传失败，重试次数：{}, requestId:{}", retry_count, self.requestId)
                if retry_count >= MAX_RETRIES:
                    self.logger.exception("vod视频上传重试失败: {}, requestId:{}", e, self.requestId)
                    raise ServiceException(ExceptionType.VIDEO_UPDATE_EXCEPTION.value[0],
                                           ExceptionType.VIDEO_UPDATE_EXCEPTION.value[1])


def get_play_url(args):
    thAliyunVodSdk = ThAliyunVodSdk(args[2], args[3], args[4])
    videoId = thAliyunVodSdk.upload_local_video(args[0], args[1])
    if videoId is None or len(videoId) == 0:
        return None
    return thAliyunVodSdk.get_play_info(videoId)
