package osm_sdk

import (
	"git.sxidc.com/go-framework/baize/framework/core/api/response"
	"git.sxidc.com/go-tools/utils/http_client"
	"git.sxidc.com/go-tools/utils/strutils"
	"github.com/pkg/errors"
	"io"
	"time"
)

const TimeoutSec = 30

var timeoutDuration = TimeoutSec * time.Second

const servicePrefix = "/osm/api/v1"

var prefix string
var namespace string
var name string
var baseUrl string
var httpClient *http_client.Client

type (
	ConfigKey struct {
		Namespace string `json:"namespace" form:"namespace" binding:"required"`
		Name      string `json:"name" form:"name" binding:"required"`
	}

	DeleteMultiObjJsonBody struct {
		ConfigKey
		ObjNames []string `json:"objNames" binding:"required"`
		Prefix   string   `json:"prefix"`
	}
	CopyJsonBody struct {
		ConfigKey
		SrcObjName   string   `json:"srcObjName" binding:"required"`
		DstObjName   string   `json:"dstObjName" binding:"required"`
		RequireInfos []string `json:"requireInfos"`
		Prefix       string   `json:"prefix"`
	}
	MoveJsonBody struct {
		ConfigKey
		SrcObjName   string   `json:"srcObjName" binding:"required"`
		DstObjName   string   `json:"dstObjName" binding:"required"`
		RequireInfos []string `json:"requireInfos"`
		Prefix       string   `json:"prefix"`
	}
	ZoomUrlJsonBody struct {
		ConfigKey
		ObjName      string   `json:"srcObjName" binding:"required"`
		Process      string   `json:"dstObjName" binding:"required"`
		RequireInfos []string `json:"requireInfos"`
		Prefix       string   `json:"prefix"`
	}
)

func Destroy() {
	if httpClient == nil {
		return
	}
	http_client.Destroy(httpClient)
	httpClient = nil
}

func Init(configPrefix, configNamespace, configName, configBaseUrl string) error {
	prefix = configPrefix
	namespace = configNamespace
	name = configName
	baseUrl = configBaseUrl + servicePrefix

	if httpClient == nil {
		httpClient = http_client.New()
	}

	return nil
}

func GetUrl(objName string) (string, error) {
	return getUrl(objName)
}

func GetUrlWithPrefix(objName string) (string, error) {
	return getUrl(prefix + objName)
}

func getUrl(objName string) (string, error) {
	if strutils.IsStringEmpty(objName) {
		return "", nil
	}

	getResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).
		Get(baseUrl+"/operation/url/get",
			http_client.WithRequestQueryParams(map[string]string{
				"namespace": namespace,
				"name":      name,
				"objName":   objName,
			}))
	if err != nil {
		return "", err
	}

	resp := new(response.InfoResponse[string])
	err = getResponse.Json(resp)
	if err != nil {
		return "", err
	}

	if !resp.Success {
		return "", errors.New(resp.Msg)
	}

	return resp.Info, nil
}

//func ZoomUrl(obj, s string) (string, error) {
//	if strutils.HasBlank(obj) {
//		log.Println("oss发现违规参数")
//		return "", nil
//	}
//	return Bkt.SignURL(prefix+obj, oss.HTTPGet, 60, oss.Process(s))
//}
//
//func ZoomUrlPfx(obj, s string, addPfx bool) (string, error) {
//	if strutils.HasBlank(obj) {
//		log.Println("oss发现违规参数")
//		return "", nil
//	}
//
//	if addPfx {
//		return Bkt.SignURL(prefix+obj, oss.HTTPGet, 60, oss.Process(s))
//	}
//
//	return Bkt.SignURL(obj, oss.HTTPGet, 60, oss.Process(s))
//
//}

func ZoomUrl(objName, profess string) (string, error) {
	return zoomUrl(objName, profess)
}

func ZoomUrlWithPrefix(objName, profess string) (string, error) {
	return zoomUrl(prefix+objName, profess)
}

func zoomUrl(objName, process string) (string, error) {
	if strutils.IsStringEmpty(objName) {
		return "", nil
	}

	postResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).
		Post(baseUrl+"/operation/obj/zoomUrl", ZoomUrlJsonBody{
			ConfigKey: ConfigKey{
				Namespace: namespace,
				Name:      name,
			},
			ObjName:      objName,
			Process:      process,
			RequireInfos: nil,
		})
	if err != nil {
		return "", err
	}

	resp := new(response.InfoResponse[string])
	err = postResponse.Json(resp)
	if err != nil {
		return "", err
	}

	if !resp.Success {
		return "", errors.New(resp.Msg)
	}

	return resp.Info, nil

}

//func Exist(obj string) (bool, error) {
//	if strutils.HasBlank(obj) {
//		return false, nil
//	}
//
//	return Bkt.IsObjectExist(prefix + obj)
//}

func Exist(objName string) (bool, error) {
	return exist(objName)
}

func ExistWithPrefix(objName string) (bool, error) {
	return exist(prefix + objName)
}

func exist(objName string) (bool, error) {
	if strutils.IsStringEmpty(objName) {
		return false, nil
	}
	getResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).Get(baseUrl+"/operation/obj/check", http_client.WithRequestQueryParams(map[string]string{
		"namespace": namespace,
		"name":      name,
		"objName":   objName}))
	if err != nil {
		return false, err
	}

	resp := new(response.InfoResponse[bool])
	err = getResponse.Json(resp)
	if err != nil {
		return false, err
	}

	if !resp.Success {
		return false, errors.New(resp.Msg)
	}

	return true, nil
}

func DeleteMulti(objNames ...string) error {
	return deleteMulti(objNames...)
}

func DeleteMultiWithPrefix(userId string, objNames ...string) error {
	for _, objName := range objNames {
		objName = prefix + objName
	}

	return deleteMulti(objNames...)
}

func deleteMulti(objNames ...string) error {
	if len(objNames) == 0 {
		return nil
	}
	postResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).Post(baseUrl+"/operation/obj/deleteMulti", DeleteMultiObjJsonBody{
		ConfigKey: ConfigKey{
			Namespace: namespace,
			Name:      name,
		},
		Prefix:   prefix,
		ObjNames: objNames,
	})
	if err != nil {
		return err
	}

	resp := new(response.MsgResponse)
	err = postResponse.Json(resp)
	if err != nil {
		return err
	}

	if !resp.Success {
		return errors.New(resp.Msg)
	}

	return nil
}

func ListDir(dirPath string) ([]string, error) {
	return listDir(dirPath)
}

func ListDirWithPrefix(dirPath string) ([]string, error) {
	return listDir(prefix + dirPath)
}

func listDir(dirPath string) ([]string, error) {
	if strutils.IsStringEmpty(dirPath) {
		return nil, nil
	}

	getResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).Get(baseUrl+"/operation/objPath/list", http_client.WithRequestQueryParams(map[string]string{
		"namespace": namespace,
		"name":      name,
		"dirPath":   dirPath,
	}))
	if err != nil {
		return nil, err
	}

	resp := new(response.InfoResponse[[]string])
	err = getResponse.Json(resp)
	if err != nil {
		return nil, err
	}

	if !resp.Success {
		return nil, errors.New(resp.Msg)
	}

	return resp.Info, nil
}

func LsDetails(dirPath string) ([]ObjectInfo, error) {
	return lsDetails(dirPath)
}

func LsDetailsWithPrefix(dirPath string) ([]ObjectInfo, error) {
	return lsDetails(prefix + dirPath)
}

type ObjectInfo struct {
	Key  string
	Type string
	Size int64
}

func lsDetails(dirPath string) ([]ObjectInfo, error) {
	if strutils.IsStringEmpty(dirPath) {
		return []ObjectInfo{}, nil
	}

	getResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).
		Get(baseUrl+"/operation/objPath/listDetail", http_client.WithRequestQueryParams(map[string]string{
			"namespace": namespace,
			"name":      name,
			"dirPath":   dirPath,
		}))
	if err != nil {
		return nil, err
	}

	resp := new(response.InfoResponse[[]ObjectInfo])
	err = getResponse.Json(resp)
	if err != nil {
		return nil, err
	}

	if !resp.Success {
		return nil, errors.New(resp.Msg)
	}

	return resp.Info, nil

}

//func Mv(f, t string) error {
//	if err := Cp(f, t); err != nil {
//		return err
//	}
//
//	return Bkt.DeleteObject(prefix + f)
//}

func Move(srcObjName, dstObjName string) (string, error) {
	return dstObjName, move(srcObjName, dstObjName, nil)
}

func MoveWithPrefix(srcObjName, dstObjName string) (string, error) {
	return prefix + dstObjName, move(prefix+srcObjName, prefix+dstObjName, nil)
}

func move(srcObjName, dstObjName string, requireInfos []string) error {
	if strutils.IsStringEmpty(srcObjName) {
		return nil
	}
	if strutils.IsStringEmpty(dstObjName) {
		return nil
	}
	putResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).
		Put(baseUrl+"/operation/obj/move", MoveJsonBody{
			ConfigKey: ConfigKey{
				Namespace: namespace,
				Name:      name,
			},
			SrcObjName:   srcObjName,
			DstObjName:   dstObjName,
			RequireInfos: requireInfos,
			Prefix:       prefix,
		})
	if err != nil {
		return err
	}
	resp := new(response.InfoResponse[any])
	err = putResponse.Json(resp)
	if err != nil {
		return err
	}
	if !resp.Success {
		return errors.New(resp.Msg)
	}
	return nil
}

//func CpOrigin(f, t string) error {
//	_, err := Bkt.CopyObject(f, t)
//	return err
//}

func Copy(srcObjName, dstObjName string) (string, error) {
	return dstObjName, copying(srcObjName, dstObjName, nil)
}

func CopyWithPrefix(srcObjName, dstObjName string) (string, error) {
	return prefix + dstObjName, copying(prefix+srcObjName, prefix+dstObjName, nil)
}

func copying(srcObjName, dstObjName string, requireInfos []string) error {
	if strutils.IsStringEmpty(srcObjName) {
		return nil
	}
	if strutils.IsStringEmpty(dstObjName) {
		return nil
	}

	postResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).
		Post(baseUrl+"/operation/obj/copy", CopyJsonBody{
			ConfigKey: ConfigKey{
				Namespace: namespace,
				Name:      name,
			},
			SrcObjName:   srcObjName,
			DstObjName:   dstObjName,
			RequireInfos: requireInfos,
			Prefix:       prefix,
		})
	if err != nil {
		return err
	}

	resp := new(response.InfoResponse[any])
	err = postResponse.Json(resp)
	if err != nil {
		return err
	}

	if !resp.Success {
		return errors.New(resp.Msg)
	}

	return nil
}

func CopyPublic(srcObjName, dstObjName string) (string, error) {
	return dstObjName, copyPublic(srcObjName, dstObjName, nil)
}

func CopyPublicWithPrefix(srcObjName, dstObjName string) (string, error) {
	return prefix + dstObjName, copyPublic(prefix+srcObjName, prefix+dstObjName, nil)
}

func copyPublic(srcObjName, dstObjName string, requireInfos []string) error {
	if strutils.IsStringEmpty(srcObjName) {
		return nil
	}
	if strutils.IsStringEmpty(dstObjName) {
		return nil
	}

	postRequest := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration))
	postResponse, err := postRequest.Post(baseUrl+"/operation/obj/copyPublic", CopyJsonBody{
		ConfigKey: ConfigKey{
			Namespace: namespace,
			Name:      name,
		},
		SrcObjName:   srcObjName,
		DstObjName:   dstObjName,
		RequireInfos: requireInfos,
		Prefix:       prefix,
	})
	if err != nil {
		return err
	}
	resp := new(response.InfoResponse[any])
	err = postResponse.Json(resp)
	if err != nil {
		return err
	}

	if !resp.Success {
		return errors.New(resp.Msg)
	}

	return nil

}

func CreateImage(reader io.Reader, objName string) (string, error) {
	return createImage(reader, objName)
}

func CreateImageWithPrefix(reader io.Reader, objName string) (string, error) {
	return createImage(reader, prefix+objName)
}

func createImage(reader io.Reader, objName string) (string, error) {
	if strutils.IsStringEmpty(objName) {
		return "", nil
	}

	postResponse, err := httpClient.NewRequest(http_client.WithNewRequestTimeout(timeoutDuration)).
		Post(baseUrl+"/operation/obj/create/image", nil,
			http_client.WithRequestFileReader("file", objName, reader),
			http_client.WithRequestFormData(map[string]string{
				"namespace": namespace,
				"name":      name,
				"objName":   objName,
			}))
	if err != nil {
		return "", err
	}

	resp := new(response.InfoResponse[string])
	err = postResponse.Json(resp)
	if err != nil {
		return "", err
	}

	if !resp.Success {
		return "", errors.New(resp.Msg)
	}
	return resp.Info, nil
}

//func Cp(f, t string) error {
//	return CpOrigin(prefix+f, prefix+t)
//}
//
//func TouchFormatImg(reader io.Reader, to string) error {
//	if reader == nil || strutils.HasBlank(to) {
//		log.Println("oss上传发现违规参数")
//		return nil
//	}
//
//	return Bkt.PutObject(prefix+to, reader, oss.ContentType("image/jpg"))
//}

//func GetObjectBytes(obj string) ([]byte, error) {
//	if strutils.HasBlank(obj) {
//		return nil, errors.New("参数错误")
//	}
//	buf := new(bytes.Buffer)
//	body, err := Bkt.GetObject(prefix + obj)
//	if err != nil {
//		return nil, err
//	}
//	_, err = io.Copy(buf, body)
//	if err != nil {
//		return nil, err
//	}
//	err = body.Close()
//	if err != nil {
//		return nil, err
//	}
//
//	return buf.Bytes(), nil
//}

//func getObjectBytes(objName, userId string) ([]byte, error) {
//	if strutils.IsStringEmpty(objName) {
//		return nil, nil
//	}
//	if strutils.IsStringEmpty(objName) {
//		return nil, nil
//	}
//	buf := new(bytes.Buffer)
//
//	responseBytes, err := httpClient.GetWithoutHeaders(baseUrl+"/operation/obj/getContent", map[string]string{
//		"namespace": namespace,
//		"name":      name,
//		"objName":   objName,
//		"userId":    userId,
//	})
//	if err != nil {
//		return nil, err
//	}
//
//	resp := new(response.InfoResponse[[]byte])
//	err = json.Unmarshal(responseBytes, resp)
//	if err != nil {
//		return nil, err
//	}
//
//	if !resp.Success {
//		return nil, errors.New(resp.Msg)
//	}
//
//	//return resp.Info, nil
//	_, err = io.Copy(buf, resp.Info)
//	if err != nil {
//		return nil, err
//	}
//	err = body.Close()
//	if err != nil {
//		return nil, err
//	}
//
//	return buf.Bytes(), nil
//}

//func MvWithoutPrefix(f, t string) error {
//	if _, err := Bkt.CopyObject(f, t); err != nil {
//		return err
//	}
//
//	return Bkt.DeleteObject(f)
//}