package exceltool

import (
	"errors"
	"fmt"
	"math/rand"
	"time"

	excelize "github.com/360EntSecGroup-Skylar/excelize/v2"
	"github.com/astaxie/beego/orm"
)

type ExcelHead struct {
	Name string
	Key  string
}

//ExcelMaker 构建excel文档
type ExcelMaker struct {
	Xlsx     *excelize.File
	fileName string
	header   []ExcelHead
}

//NewExcelMaker ....
func NewExcelMaker() *ExcelMaker {
	return &ExcelMaker{
		Xlsx: excelize.NewFile(),
	}
}

func (e *ExcelMaker) SetListHead(h []ExcelHead) {
	e.header = h
}

func (e *ExcelMaker) SetFileName(n string) {
	e.fileName = n
}

func (e *ExcelMaker) GetFileName() string {
	return e.fileName
}

//MakeListExcel 根据列表形式的数据创建excel文档
//@sourData []map[string]string; 原始数据,要输入excel文档的数据
func (e *ExcelMaker) MakeListExcel(sourData []map[string]string) (err error) {
	if len(e.header) == 0 {
		return errors.New("xlsHeader 数据格式错误")
	}
	headEn := []string{}     //数据字段英文名
	headCn := []string{}     //excel字段中文描述
	alphaSlice := []string{} //excel列字母索引
	for key, val := range e.header {
		headEn = append(headEn, val.Key)
		headCn = append(headCn, val.Name)
		//alpha, err := excelize.ColumnNumberToName(key)
		//if err != nil {
		//	return err
		//}
		alpha := ToAlphaString(key)
		alphaSlice = append(alphaSlice, alpha)
	}

	//设置excel文档第一行的字段中文描述
	for index := range headCn {
		//索引转列名,索引从0开始
		cellAlpha := fmt.Sprintf("%s%d", alphaSlice[index], 1) // 单元格行坐标从1开始,如:a1,指第一行a列。
		e.Xlsx.SetCellStr("Sheet1", cellAlpha, headCn[index])

	}
	//从excel第二行开始设置实际数据的值
	for key1 := range sourData {
		for i := 0; i < len(headEn); i++ {
			cellAlpha := fmt.Sprintf("%s%d", alphaSlice[i], key1+2) // 单元格行坐标从1开始,如:a1,指第一行a列。
			e.Xlsx.SetCellStr("Sheet1", cellAlpha, sourData[key1][headEn[i]])
		}
	}
	e.SetFileName(GetRandomString(8) + ".xlsx")
	return nil
}

//MakeListExcelForBeego 根据数据创建列表形式的excel文档
//@sourData []orm.Params; 原始数据,要输入excel文档的数据
func (e *ExcelMaker) MakeListExcelForBeego(sourData []orm.Params) (err error) {
	if len(e.header) == 0 {
		return errors.New("xlsHeader 数据格式错误")
	}
	headEn := []string{}     //数据字段英文名
	headCn := []string{}     //excel字段中文描述
	alphaSlice := []string{} //excel列字母索引
	for key, val := range e.header {
		headEn = append(headEn, val.Key)
		headCn = append(headCn, val.Name)
		alpha, err := excelize.ColumnNumberToName(key)
		if err != nil {
			return err
		}
		alphaSlice = append(alphaSlice, alpha)
	}

	//设置excel文档第一行的字段中文描述
	for index := range headCn {
		//索引转列名,索引从0开始
		cellAlpha := fmt.Sprintf("%s%d", alphaSlice[index], 1) // 单元格行坐标从1开始,如:a1,指第一行a列。
		e.Xlsx.SetCellStr("Sheet1", cellAlpha, headCn[index])

	}
	//从excel第二行开始设置实际数据的值
	for key1 := range sourData {
		for i := 0; i < len(headEn); i++ {
			cellAlpha := fmt.Sprintf("%s%d", alphaSlice[i], key1+2) // 单元格行坐标从1开始,如:a1,指第一行a列。
			if sourData[key1][headEn[i]] == nil {
				sourData[key1][headEn[i]] = ""
			}
			e.Xlsx.SetCellStr("Sheet1", cellAlpha, fmt.Sprintf("%s", sourData[key1][headEn[i]]))
		}
	}
	if len(e.fileName) == 0 {
		e.fileName = GetRandomString(8) + ".xlsx"
	}
	return nil
}

//GetRandomString 生成随机字符串
func GetRandomString(lenght int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < lenght; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

func ToAlphaString(value int) string {
	if value < 0 {
		return ""
	}
	var ans string
	i := value + 1
	for i > 0 {
		ans = string((i-1)%26+65) + ans
		i = (i - 1) / 26
	}
	return ans
}