package utils

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"fonchain-fiee/pkg/e"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tealeg/xlsx"
)

const (
	ExcelPrefix = "xlsx"
)

func SHA256V(str []byte) string {
	h := sha256.New()
	h.Write(str)
	return hex.EncodeToString(h.Sum(nil))
}

func Get(url string) string {
	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	var buffer [512]byte
	result := bytes.NewBuffer(nil)
	for {
		n, err := resp.Body.Read(buffer[0:])
		result.Write(buffer[0:n])
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}
	}

	return result.String()
}

// PostForm 发送post请求
func PostForm(urlStr string, data url.Values) (string, error) {
	resp, err := http.PostForm(urlStr, data)

	if err != nil {
		// handle error
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
	}
	return string(body), err
}

func CheckDirPath(path string, create bool) (exists bool, err error) {
	exists = false
	if path == "" {
		err = errors.New(e.GetMsg(e.InvalidParams))
		return
	}
	if _, err = os.Stat(path); os.IsNotExist(err) {
		if !create {
			return
		}
		if err = os.MkdirAll(path, os.ModePerm); err != nil {
			return
		}
		// Linux系统下需要显式设置目录权限，确保可读写
		if err = os.Chmod(path, 0755); err != nil {
			// 权限设置失败不影响主流程，只记录警告
			err = nil
		}
	}
	exists = true
	return
}

// ToExcelByType 转成Excel类型
func ToExcelByType(titleList []string, dataList []interface{}, dataType string, filePath string) (content io.ReadSeeker, err error) {
	// 生成一个新的文件
	file := xlsx.NewFile()
	// 添加sheet页
	sheet, _ := file.AddSheet("Sheet1")
	// 插入表头
	titleRow := sheet.AddRow()
	for _, v := range titleList {
		cell := titleRow.AddCell()
		cell.Value = v
	}
	// 插入内容
	for _, v := range dataList {
		row := sheet.AddRow()
		if dataType == "struct" {
			row.WriteStruct(v, -1)
		} else if dataType == "slice" {
			row.WriteSlice(v, -1)
		}
	}
	var buffer bytes.Buffer
	_ = file.Write(&buffer)
	if filePath != "" {
		if err = file.Save(filePath); err != nil {
			return
		}
	} else {
		content = bytes.NewReader(buffer.Bytes())
	}
	return
}

// ResponseXls  content 为上面生成的io.ReadSeeker， fileTag 为返回前端的文件名
func ResponseXls(c *gin.Context, content io.ReadSeeker, fileTag string) {
	fileName := fmt.Sprintf("%s.%s", fileTag, ExcelPrefix)
	// 返回 Excel 文件流给前端
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
	c.Header("File-Name", fmt.Sprintf("%s", fileName))
	c.Header("Access-Control-Expose-Headers", "File-Name")
	//_ = c.Writer(c.Writer)
	//c.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
	//c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	http.ServeContent(c.Writer, c.Request, fileName, time.Now(), content)
}

func CreateDirPath(path string) (err error) {
	if _, err = os.Stat(path); os.IsNotExist(err) {
		if err = os.MkdirAll(path, os.ModePerm); err != nil {
			return
		}
		// Linux系统下需要显式设置目录权限，确保可读写
		if err = os.Chmod(path, 0755); err != nil {
			// 权限设置失败不影响主流程，只记录警告
			err = nil
		}
	}
	return
}

func CopyFile(src, dstDir string) (string, error) {
	in, err := os.Open(src)
	if err != nil {
		return "", err
	}
	defer in.Close()
	if err := os.MkdirAll(dstDir, 0755); err != nil {
		return "", err
	}
	dst := filepath.Join(dstDir, filepath.Base(src))
	out, err := os.Create(dst)
	if err != nil {
		return "", err
	}
	defer out.Close()
	if _, err = io.Copy(out, in); err != nil {
		return "", err
	}
	if err = out.Sync(); err != nil {
		return "", err
	}
	return dst, nil
}

func FileNameFromURL(rawURL string) (string, error) {
	u, err := url.Parse(rawURL)
	if err != nil {
		return "", err
	}
	return path.Base(u.Path), nil
}
