# -*- coding: utf-8 -*-
from json import loads
from os.path import join
from traceback import format_exc

import oss2
import time

from aliyunsdkvod.request.v20170321.GetPlayInfoRequest import GetPlayInfoRequest
from loguru import logger

from common.YmlConstant import aliyun_yml_path
from exception.CustomerException import ServiceException
from enums.ExceptionEnum import ExceptionType
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest

from util.RWUtils import getConfigs
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest


class AliyunOssSdk:

    __slots__ = ('bucket', '__request_id', '__config')

    def __init__(self, *args):
        base_dir, env, self.__request_id = args
        self.bucket = None
        self.__config = getConfigs(join(base_dir, aliyun_yml_path % env))
        self.get_oss_bucket()

    def get_oss_bucket(self):
        if self.bucket is None:
            auth = oss2.Auth(self.__config["access_key"], self.__config["access_secret"])
            self.bucket = oss2.Bucket(auth, self.__config["oss"]["endpoint"],
                                      self.__config["oss"]["bucket"],
                                      connect_timeout=self.__config["oss"]["connect_timeout"])

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


class ThAliyunVodSdk:

    __slots__ = ('__config', '__request_id')

    def __init__(self, base_dir, env, request_id):
        self.__request_id = request_id
        self.__config = getConfigs(join(base_dir, aliyun_yml_path % env))

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

    def get_play_info(self, videoId):
        logger.info("开始获取视频地址，videoId:{}, requestId:{}", videoId, self.__request_id)
        clt = self.init_vod_client(self.__config["access_key"], self.__config["access_secret"])
        start = time.time()
        retry_num = 0
        while True:
            try:
                request: GetPlayInfoRequest = GetPlayInfoRequest.GetPlayInfoRequest()
                request.set_accept_format('JSON')
                request.set_VideoId(videoId)
                request.set_AuthTimeout(3600 * 5)
                response = loads(clt.do_action_with_exception(request))
                play_url = response["PlayInfoList"]["PlayInfo"][0]["PlayURL"]
                logger.info("获取视频地址成功，视频地址: {}, requestId: {}", play_url, self.__request_id)
                return play_url
            except Exception as e:
                logger.info("获取视频地址失败，5秒后重试, requestId: {}", self.__request_id)
                retry_num += 1
                time.sleep(5)
                current_time = time.time()
                if "HTTP Status: 403" not in str(e) and retry_num > 12:
                    logger.error("获取视频地址失败: {}, requestId: {}", format_exc(), self.__request_id)
                    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) or
                                                     "ProduceFail" in str(e)):
                    logger.error("获取视频地址失败: {}, requestId: {}", format_exc(), self.__request_id)
                    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 * 5:
                    logger.error("获取视频地址失败超时异常: {}，超时时间：{}, requestId: {}", format_exc(),
                                 diff_time, self.__request_id)
                    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):
        logger.info("开始执行vod视频上传, filePath: {}, requestId: {}", filePath, self.__request_id)
        uploader = AliyunVodUploader(self.__config["access_key"], self.__config["access_secret"], self.__request_id)
        uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title)
        logger.info("视频分类:{}, requestId:{}", self.__config["vod"]["cateId"], self.__request_id)
        uploadVideoRequest.setCateId(self.__config["vod"]["cateId"])
        # 可以设置视频封面，如果是本地或网络图片可使用UploadImageRequest上传图片到视频点播，获取到ImageURL
        # ImageURL示例：https://example.com/sample-****.jpg
        # uploadVideoRequest.setCoverURL('<your Image URL>')
        # 标签
        # uploadVideoRequest.setTags('tag1,tag2')
        MAX_RETRIES = 3
        retry_count = 0
        while True:
            try:
                result = uploader.uploadLocalVideo(uploadVideoRequest)
                logger.info("vod视频上传成功, videoId:{}, requestId:{}", result.get("VideoId"), self.__request_id)
                return result.get("VideoId")
            except Exception:
                retry_count += 1
                time.sleep(1)
                uploader = AliyunVodUploader(self.__config["access_key"], self.__config["access_secret"],
                                             self.__request_id)
                uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title)
                uploadVideoRequest.setCateId(self.__config["vod"]["cateId"])
                logger.error("vod视频上传失败:{}，重试次数：{}, requestId:{}", format_exc(), retry_count,
                             self.__request_id)
                if retry_count >= MAX_RETRIES:
                    raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
                                           ExceptionType.SERVICE_INNER_EXCEPTION.value[1])

    def get_play_url(self, filePath, file_title):
        videoId = self.upload_local_video(filePath, file_title)
        if videoId is None or len(videoId) == 0:
            raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
                                   ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
        return self.get_play_info(videoId)

# if __name__ == "__main__":
#     aa = ThAliyunVodSdk('/home/th/tuo_heng/dev/tuoheng_alg', 'dev', "1")
#     print(aa.get_play_info('6928821035b171ee9f3b6632b68f0102'))
