package service

import (
	"doc-service/common/log"
	"encoding/json"
	"errors"
	"fmt"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	imm20200930 "github.com/alibabacloud-go/imm-20200930/v4/client"
	openapiutil "github.com/alibabacloud-go/openapi-util/service"
	util "github.com/alibabacloud-go/tea-utils/v2/service"
	"github.com/alibabacloud-go/tea/tea"
	"gopkg.in/ini.v1"
	"net/url"
	"os"
	"strings"
)

type Conversion struct {
	AccessKeyId     string
	AccessKeySecret string
	Endpoint        string
	Bucket          string
}

func NewConversion() *Conversion {
	config, iniErr := ini.Load("./conf/app.ini")
	if iniErr != nil {
		log.Error("Fail to read file: %v", iniErr)
		os.Exit(1)
	}
	host := config.Section("AliYun").Key("host").String()
	accessId := config.Section("AliYun").Key("accessId").String()
	accessKeySecret := config.Section("AliYun").Key("accessKeySecret").String()
	bucketPrivate := config.Section("AliYun").Key("bucketPrivate").String()
	return &Conversion{
		Endpoint:        host,
		AccessKeyId:     accessId,
		AccessKeySecret: accessKeySecret,
		Bucket:          bucketPrivate,
	}
}

func (o *Conversion) CreateClient() (_result *openapi.Client, _err error) {
	config := &openapi.Config{
		AccessKeyId:     tea.String(o.AccessKeyId),
		AccessKeySecret: tea.String(o.AccessKeySecret),
	}
	config.Endpoint = tea.String(o.Endpoint)
	_result = &openapi.Client{}
	_result, _err = openapi.NewClient(config)
	return _result, _err
}

// CreateApiInfo API 相关
func (o *Conversion) CreateApiInfo() (_result *openapi.Params) {
	params := &openapi.Params{
		Action:      tea.String("CreateOfficeConversionTask"),
		Version:     tea.String("2020-09-30"),
		Protocol:    tea.String("HTTPS"),
		Method:      tea.String("POST"),
		AuthType:    tea.String("AK"),
		Style:       tea.String("RPC"),
		Pathname:    tea.String("/"),
		ReqBodyType: tea.String("json"),
		BodyType:    tea.String("json"),
	}
	return params
}

// GetBucket 获取bucket信息
func (o *Conversion) GetBucket(isPrivate bool) string {
	if isPrivate {
		return "oss://" + "test-bucket-v1"
	}
	return "oss://" + "test-bucket-v1-pub"
}

type ConversionRequest struct {
	ProjectName string
	SourceType  string
	TargetType  string
	SourceURI   string
	TargetURI   string
	IsPrivate   bool
}

type GetTaskRequest struct {
	ProjectName       string
	TaskType          string
	TaskId            string
	RequestDefinition bool
}

func (o *Conversion) checkParam(arg ConversionRequest) error {
	if arg.SourceURI == "" {
		return errors.New("SourceURI 不能为空")
	}
	if arg.ProjectName == "" {
		return errors.New("ProjectName 不能为空")
	}
	if arg.SourceType == "" {
		return errors.New("SourceType 不能为空")
	}
	if arg.TargetType == "" {
		return errors.New("TargetType 不能为空")
	}
	return nil
}

func (o *Conversion) checkGetTaskParam(arg GetTaskRequest) error {

	if arg.ProjectName == "" {
		return errors.New("ProjectName 不能为空")
	}
	if arg.TaskType == "" {
		return errors.New("SourceType 不能为空")
	}
	if arg.TaskId == "" {
		return errors.New("TargetType 不能为空")
	}
	return nil
}

// 文件转换

// DoConversion 文件转换
func (o *Conversion) DoConversion(arg ConversionRequest) (map[string]interface{}, error) {
	ret := make(map[string]interface{}, 0)
	//校验参数
	checkErr := o.checkParam(arg)
	if checkErr != nil {
		return ret, checkErr
	}

	client := NewConversion()
	params := client.CreateApiInfo()

	sourceParseUrl, parseErr := url.Parse(arg.SourceURI)
	if parseErr != nil {
		return ret, parseErr
	}
	targetParseUrl, parseTargetErr := url.Parse(arg.TargetURI)
	if parseTargetErr != nil {
		return ret, parseTargetErr
	}
	// query params
	queries := map[string]interface{}{}
	queries["ProjectName"] = arg.ProjectName
	queries["SourceURI"] = o.GetBucket(arg.IsPrivate) + sourceParseUrl.Path
	queries["TargetURI"] = o.GetBucket(arg.IsPrivate) + targetParseUrl.Path
	queries["SourceType"] = arg.SourceType
	queries["TargetType"] = arg.TargetType
	runtime := &util.RuntimeOptions{}
	request := &openapi.OpenApiRequest{
		Query: openapiutil.Query(queries),
	}

	ossClient, _err := client.CreateClient()
	if _err != nil {
		return ret, _err
	}

	log.Info("转换请求参数: %s", queries)
	// 返回值为 Map 类型，可从 Map 中获得三类数据：响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
	res, err := ossClient.CallApi(params, request, runtime)
	log.Info("DoConversion result返回：%s", res)
	if err != nil {
		return ret, err
	}
	return res, err

}

func (o *Conversion) CreateImClient() (_result *imm20200930.Client, _err error) {
	config := &openapi.Config{
		AccessKeyId:     tea.String(o.AccessKeyId),
		AccessKeySecret: tea.String(o.AccessKeySecret),
	}
	config.Endpoint = tea.String(o.Endpoint)

	_result = &imm20200930.Client{}
	_result, _err = imm20200930.NewClient(config)
	return _result, _err
}

// 创建项目
func (o *Conversion) CreateProject() (_err error) {
	client, createError := o.CreateImClient()
	if createError != nil {
		return createError
	}

	createProjectRequest := &imm20200930.CreateProjectRequest{}
	ProjectName := "DOC_TO_PDF"
	createProjectRequest.ProjectName = &ProjectName
	runtime := &util.RuntimeOptions{}

	tryErr := func() (_e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				_e = r
			}
		}()
		createdResp, _err := client.CreateProjectWithOptions(createProjectRequest, runtime)
		if _err != nil {
			return _err
		}
		log.Info("创建项目返回参数 %s", createdResp)
		return nil
	}()

	if tryErr != nil {
		var sdkErr = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			sdkErr = _t
		} else {
			sdkErr.Message = tea.String(tryErr.Error())
		}
		// 诊断地址
		var data interface{}
		d := json.NewDecoder(strings.NewReader(tea.StringValue(sdkErr.Data)))
		decodeError := d.Decode(&data)
		if decodeError != nil {
			return decodeError
		}
		if m, ok := data.(map[string]interface{}); ok {
			log.Error("创建项目出现异常%s", m["Code"])
			resultCode, assertCodeError := util.AssertAsString(m["Code"])
			if assertCodeError != nil {
				return assertCodeError
			}
			if *resultCode == "ResourceAlreadyExists" {
				return nil
			}
			return errors.New(*resultCode)
		}
		errMsg, assertError := util.AssertAsString(sdkErr.Message)
		if assertError != nil {
			return assertError
		}
		log.Error("创建项目出现异常%s", &errMsg)
	}
	return nil
}

func (o *Conversion) GetTaskProject(args GetTaskRequest) (*imm20200930.GetTaskResponse, error) {
	client, _err := o.CreateImClient()
	resp := &imm20200930.GetTaskResponse{}
	if _err != nil {
		return resp, _err
	}
	getTaskRequest := &imm20200930.GetTaskRequest{}
	getTaskRequest.ProjectName = &args.ProjectName
	getTaskRequest.TaskId = &args.TaskId
	getTaskRequest.TaskType = &args.TaskType
	getTaskRequest.RequestDefinition = &args.RequestDefinition
	runtime := &util.RuntimeOptions{}
	resp, tryErr := func() (*imm20200930.GetTaskResponse, error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				_err = r
			}
		}()
		// 复制代码运行请自行打印 API 的返回值
		resp, _err = client.GetTaskWithOptions(getTaskRequest, runtime)
		if _err != nil {
			return nil, _err
		}
		fmt.Println("获取任务返回参数", resp)
		return resp, _err
	}()

	if tryErr != nil {
		var err = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			err = _t
		} else {
			err.Message = tea.String(tryErr.Error())
		}
		// 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
		// 错误 message
		log.Error("错误码%s", tea.StringValue(err.Message))
		// 诊断地址
		var data interface{}
		d := json.NewDecoder(strings.NewReader(tea.StringValue(err.Data)))
		_err := d.Decode(&data)
		if m, ok := data.(map[string]interface{}); ok {
			recommend, _ := m["Recommend"]
			log.Info("回访详细%v", recommend)
		}
		_, _err = util.AssertAsString(err.Message)
		if _err != nil {
			return resp, _err
		}
	}
	return resp, _err
}
