package filesdk

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"strings"
	"sync"
)

var (
	persistent = "fs/api/v1/files/persistent" //文件持久化路径
	upload     = "fs/api/v1/files"            // 文件上传api路径
)

type persistentStruct struct {
	Hash string `json:"hash"`
}

type Config struct {
	Host string
}

type ConfigHandle struct {
	Host string
}

var (
	once           sync.Once
	internalHandle *ConfigHandle
)

func (c *Config) Init() {
	//代码运行中需要的时候执行，且只执行一次
	once.Do(func() {
		internalHandle = &ConfigHandle{
			Host: c.Host,
		}
	})
}

// GetHandle get handle
func GetHandle() *ConfigHandle {
	return internalHandle
}

//HandlePersistent 设置文件持久化
func (c *ConfigHandle) HandlePersistent(hash string) error {
	if hash == "" {
		return errors.New("缺少请求参数")
	}
	param := persistentStruct{
		Hash: hash,
	}
	s, err := json.Marshal(param)
	if err != nil {
		return err
	}
	url := fmt.Sprintf("%s/%s", c.Host, persistent)
	reqBody := strings.NewReader(string(s))
	req, err := http.NewRequest(http.MethodPut, url, reqBody)
	if err != nil {
		return err
	}
	req.Header.Set("Content-type", "application/json")
	client := &http.Client{}
	response, err := client.Do(req)
	if err != nil {
		return err
	}
	_, err = ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	return nil
}

type FileInfo struct {
	URL  string `json:"url"`
	Name string `json:"name"`
	Hash string `json:"hash"`
	Size int64  `json:"size"`
}

// Upload 文件上传
// headers 参数支持：FILE-EXPIRE，FILE-HASH
func (c *ConfigHandle) Upload(fileName string, bucket string, headers map[string]string, fileData []byte) (*FileInfo, error) {
	if len(fileData) == 0 {
		return nil, errors.New("非法文件")
	}
	fileBytes := &bytes.Buffer{}
	writer := multipart.NewWriter(fileBytes)
	part, err := writer.CreateFormFile("fileData", fileName)
	if err != nil {
		return nil, err
	}
	if _, err = part.Write(fileData); err != nil {
		return nil, err
	}
	baseUrlField, err := writer.CreateFormField("base_url")
	if err != nil {
		return nil, err
	}
	_, err = baseUrlField.Write([]byte(bucket))
	if err != nil {
		return nil, err
	}
	formKey, err := writer.CreateFormField("form_key")
	if err != nil {
		return nil, err
	}
	_, err = formKey.Write([]byte("fileData"))
	if err != nil {
		return nil, err
	}

	err = writer.Close()
	if err != nil {
		return nil, err
	}
	url := fmt.Sprintf("%s/%s", c.Host, upload)
	req, err := http.NewRequest("POST", url, fileBytes)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-type", writer.FormDataContentType())
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	client := &http.Client{}
	response, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	resp, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	var result *FileInfo
	if err = json.Unmarshal(resp, &result); err != nil {
		return nil, err
	}
	return result, nil
}
