package aliyun

import (
	"encoding/json"
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
	"github.com/astaxie/beego"
	"github.com/prometheus/common/log"
	"gitlab.fjmaimaimai.com/mmm-go/gocomm/common"
	comm_time "gitlab.fjmaimaimai.com/mmm-go/gocomm/time"
	"net/url"
	"opp/internal/utils"
	"path"
	"path/filepath"
	"strings"
	"time"
)

//客户端
func DefaultVodClient() (client *vod.Client, err error) {
	return InitVodClient(AccessKeyID, AccessKeySecret)
}

//初始化客户端
func InitVodClient(accessKeyId string, accessKeySecret string) (client *vod.Client, err error) {
	// 点播服务接入区域
	regionId := RegionID
	// 创建授权对象
	credential := &credentials.AccessKeyCredential{
		accessKeyId,
		accessKeySecret,
	}
	// 自定义config
	config := sdk.NewConfig()
	config.AutoRetry = true     // 失败是否自动重试
	config.MaxRetryTime = 3     // 最大重试次数
	config.Timeout = 3000000000 // 连接超时,单位:纳秒;默认为3秒
	// 创建vodClient实例
	return vod.NewClientWithOptions(regionId, config, credential)
}

//获取视频上传地址和凭证,并创建视频信息
func CreateUploadVideo(client *vod.Client, r *CreateUploadVideoRequest) (response *CreateUploadVideoResponse, err error) {
	request := vod.CreateCreateUploadVideoRequest()
	filePath := getFileName(FileVideo, r.FileName)
	if filepath.Ext(r.FileName) == ".mp3" {
		filePath = getFileName(FileVoice, r.FileName)
	}
	request.Title = filePath
	request.FileName = filePath
	request.AcceptFormat = "JSON"
	rsp, err := client.CreateUploadVideo(request)
	if err != nil {
		return
	}
	response = &CreateUploadVideoResponse{
		RequestId:     rsp.RequestId,
		VideoId:       rsp.VideoId,
		UploadAddress: rsp.UploadAddress,
		UploadAuth:    rsp.UploadAuth,
	}
	if up, e := ParseUploadAddress(rsp.UploadAddress); e != nil {
		log.Error(e)
	} else {
		response.FileURL = up.GetFileUrl(beego.AppConfig.String("cname"))
	}
	return
}

func RefreshUploadVideo(client *vod.Client, r *RefreshUploadVideoRequest) (response *RefreshUploadVideoResponse, err error) {
	request := vod.CreateRefreshUploadVideoRequest()
	request.VideoId = r.VideoId
	request.AcceptFormat = "JSON"

	var rsp *vod.RefreshUploadVideoResponse
	rsp, err = client.RefreshUploadVideo(request)
	if err != nil {
		return
	}
	if err = utils.JsonDeepCopy(&response, &rsp); err != nil {
		return
	}
	if up, e := ParseUploadAddress(rsp.UploadAddress); e != nil {
		log.Error(e)
	} else {
		response.FileURL = up.GetFileUrl(beego.AppConfig.String("cname"))
	}
	return
}

//获取图片上传地址和凭证,并创建视频信息
func CreateUploadImage(client *vod.Client, r *CreateUploadImageRequest) (response *CreateUploadImageResponse, err error) {
	request := vod.CreateCreateUploadImageRequest()
	filePath := getFileName(FileImage, r.FileName)
	request.ImageType = "default"
	request.Title = filePath
	if filepath.Ext(r.FileName) == "" {
		err = fmt.Errorf("filename:%v invalid", r.FileName)
		return
	}
	request.ImageExt = filepath.Ext(r.FileName)[1:]
	if request.ImageExt == "" {
		err = fmt.Errorf("filename:%v invalid", r.FileName)
		return
	}
	request.AcceptFormat = "JSON"
	//request.StorageLocation = filepath.Base(request.Title)
	rsp, err := client.CreateUploadImage(request)
	if err != nil {
		return
	}
	err = utils.JsonDeepCopy(&response, &rsp)
	return
}

//获取播放信息
func GetPlayInfo(client *vod.Client, r *GetPlayInfoRequest) (response *vod.GetPlayInfoResponse, err error) {
	request := vod.CreateGetPlayInfoRequest()
	request.VideoId = r.VideoId
	request.AcceptFormat = "JSON"
	return client.GetPlayInfo(request)
}

//获取播放信息
func GetGetVideoPlayAuth(client *vod.Client, r *GetVideoPlayAuthRequest) (response GetVideoPlayAuthResponse, err error) {
	request := vod.CreateGetVideoPlayAuthRequest()
	request.VideoId = r.VideoId
	request.AcceptFormat = "JSON"
	var rsp *vod.GetVideoPlayAuthResponse
	if rsp, err = client.GetVideoPlayAuth(request); err != nil {
		log.Error(err)
		return
	}
	err = utils.JsonDeepCopy(&response, rsp)
	return
}

//fileType: video voice image
func getFileName(fileType string, filename string) string {
	date := comm_time.GetTimeByYyyymmdd()
	subfix := path.Ext(filename)
	prefix := fmt.Sprintf("%v_%v", time.Now().Unix(), common.RandomString(32))
	filename = fmt.Sprintf("%v%v", prefix, subfix)
	sourcePath := fmt.Sprintf("%v/%v/%v/%v/%v", beego.BConfig.AppName, beego.BConfig.RunMode, date, fileType, filename)
	return sourcePath
}

//上传媒体数据按路径
//@urls 需要上传得媒体地址列表
//@callBack 回调设置
//@extend 回调用返回数据
func UploadMediaByURL(urls []string, callBack *CallBack, extend interface{}) (response *vod.UploadMediaByURLResponse, err error) {
	client, e := DefaultVodClient()
	if e != nil {
		err = e
		return
	}
	request := vod.CreateUploadMediaByURLRequest()

	// 对URL进行编码
	uploadUrls := []string{}
	metaData := []map[string]interface{}{}
	for _, surl := range urls {
		encodeUrl := url.QueryEscape(surl)
		uploadUrls = append(uploadUrls, encodeUrl)
		metadata := map[string]interface{}{"SourceURL": encodeUrl} //, "Title":"UploadMediaByURL Sample Title"
		metaData = append(metaData, metadata)
	}

	// 设置上传的URL列表,用逗号分隔
	request.UploadURLs = strings.Join(uploadUrls, ",")

	// 可选项,设置URL对应的Meta信息
	jsonMetas, err := json.Marshal(metaData)
	if err != nil {
		fmt.Println("json.Marshal failed:", err)
		return
	}
	request.UploadMetadatas = string(jsonMetas)

	// 可选项,设置转码模板组
	//request.TemplateGroupId = "<TemplateGroupId>"

	//设置回调
	if callBack != nil {
		ud := UserData{
			MessageCallback: assertMarsh(callBack),
			Extend:          assertMarsh(extend),
		}
		request.UserData = assertMarsh(ud)
	}

	request.AcceptFormat = "JSON"
	return client.UploadMediaByURL(request)
}

//通过oss上传图片
func OssUploadImageByUrl(rawurl string) (response *CreateUploadImageResponse, err error) {
	var (
		vodc     *vod.Client
		imageRsp *CreateUploadImageResponse
		client   *OSSClient
	)
	u, err := url.Parse(rawurl)
	if err != nil {
		return
	}
	imageRsp, err = CreateUploadImage(vodc, &CreateUploadImageRequest{FileName: u.Path})
	if err != nil {
		return
	}
	client, err = NewStsOSSClient(imageRsp.UploadAddress, imageRsp.UploadAuth)
	if err != nil {
		return
	}
	err = client.PutObjectByUrlDefault(rawurl)
	if err != nil {
		return
	}
	return
}

func assertMarsh(v interface{}) string {
	data, e := json.Marshal(v)
	if e != nil {
		return ""
	}
	return string(data)
}