package api

import (
	"box-cost/db/model"
	"box-cost/db/repo"
	"box-cost/log"
	"bytes"
	"fmt"
	"math"
	"math/rand"
	"net/http"
	"os"
	"sync"
	"time"
	"unsafe"

	"github.com/gin-gonic/gin"
	"github.com/thecodingmachine/gotenberg-go-client/v7"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

var SignatureDir string = "https://www.3dqueen.cloud/box/v1/boxcost/public/"

func makeBillQuery(query map[string]interface{}) map[string]interface{} {
	if query["packId"] != nil {
		query["packId"], _ = primitive.ObjectIDFromHex(query["packId"].(string))
	}
	if query["planId"] != nil {
		query["planId"], _ = primitive.ObjectIDFromHex(query["planId"].(string))
	}

	// 时间范围查询
	// createTime 选中的当天时间
	st, ok1 := query["startTime"]
	delete(query, "startTime")
	et, ok2 := query["endTime"]
	delete(query, "endTime")
	if ok1 && ok2 {
		startTime := st.(string)
		endTime := et.(string)
		start, end := getTimeRange(startTime, endTime)
		query["createTime"] = bson.M{"$gte": start, "$lte": end}
	}

	if productName, ok := query["productName"]; ok {
		delete(query, "productName")
		query["productName"] = bson.M{"$regex": productName.(string)}
	}

	return query
}

// func getRowHeight(content string, width float64,lineHeight float64) float64 {
// 第一个参数为 行宽 第二个参数为 行高
func getRowHeight(content string, params ...float64) float64 {
	var perHeight float64 = 16
	if len(params) == 2 {
		perHeight = params[1]
	}
	num := float64(len([]rune(content)))
	// 一行能容纳多少字
	rowNum := params[0] / 1.5
	// 向上取整获取行数 * 每行高度
	rowHeight := math.Ceil(num/rowNum) * perHeight
	return rowHeight

}

// 保存文件为pdf
func savePdfToTmp(saveTmpDir, fileName string, data []byte) error {

	err := os.MkdirAll(saveTmpDir, os.ModePerm)
	if err != nil {
		log.Error(err)
		return err
	}
	fullFileName := fmt.Sprintf("%s/%s", saveTmpDir, fileName)
	if err := os.WriteFile(fullFileName, data, 0666); err != nil {
		log.Error(err)
		return err
	}
	return nil

}

// 保存文件
func saveExcelToTmp(saveTmpDir, fileName string, data []byte, toExcelResult chan<- int, wg *sync.WaitGroup) {

	err := os.MkdirAll(saveTmpDir, os.ModePerm)
	if err != nil {
		log.Error(err)
		fmt.Println(err)
		toExcelResult <- -1
		wg.Done()
		return
	}
	fullFileName := fmt.Sprintf("%s/%s", saveTmpDir, fileName)
	if err := os.WriteFile(fullFileName, data, 0666); err != nil {
		log.Error(err)
		fmt.Println(err)
		toExcelResult <- -1
		wg.Done()
		return
	}
	toExcelResult <- 1
	wg.Done()
}

func saveExcelToTmp1(saveTmpDir, fileName string, data []byte) error {

	err := os.MkdirAll(saveTmpDir, os.ModePerm)
	if err != nil {
		log.Error(err)
		fmt.Println(err)
		return err
	}
	fullFileName := fmt.Sprintf("%s/%s", saveTmpDir, fileName)
	if err := os.WriteFile(fullFileName, data, 0666); err != nil {
		log.Error(err)
		fmt.Println(err)
		return err
	}
	return nil
}

func isExistDir(dir string) bool {
	_, err := os.Stat(dir)
	if err != nil {
		return os.IsExist(err)
	}
	return true
}

// 去重相邻元素
func removeDuplicationSort(arr []string) []string {
	length := len(arr)
	if length == 0 {
		return arr
	}

	j := 0
	for i := 1; i < length; i++ {
		if arr[i] != arr[j] {
			j++
			if j < i {
				swap(arr, i, j)
			}
		}
	}

	return arr[:j+1]
}

func swap(arr []string, a, b int) {
	arr[a], arr[b] = arr[b], arr[a]
}

func generateSerial(c *gin.Context, ctx *ApiSession, typeName string) (serial string, err error) {
	// 获取类型
	cate := &model.Category{}
	found, err := repo.RepoSeachDoc(ctx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: "cates",
		Project:     []string{"letterName"},
		Query:       repo.Map{"name": typeName},
		Sort:        bson.M{"_id": -1},
	}, cate)
	if !found || err != nil {
		return "", fmt.Errorf("未找到该类型")
	}
	// 自增器 increment index加1
	increment := &model.Increment{}
	found, _ = repo.RepoSeachDoc(ctx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: repo.CollectionIncrement,
		Query:       repo.Map{"type": cate.LetterName},
		Project:     []string{"index"},
		Sort:        bson.M{"_id": -1},
	}, increment)
	if !found {
		repo.RepoAddDoc(ctx.CreateRepoCtx(), repo.CollectionIncrement, &model.Increment{
			Type:  cate.LetterName,
			Index: 1,
		})
		return fmt.Sprintf("%s-%06d", cate.LetterName, 1), nil
	}

	index := increment.Index + 1
	// repo.RepoUpdateSetDoc(ctx.CreateRepoCtx(), repo.CollectionIncrement, increment.Id.Hex(), &model.Increment{Index: index})
	repo.RepoUpdateSetDoc1(ctx.CreateRepoCtx(), repo.CollectionIncrement, increment.Id.Hex(), &model.Increment{Index: index}, &repo.RecordLogReq{
		Path:     c.Request.URL.Path,
		TargetId: increment.Id.Hex(),
	})

	// 拼接为序号
	return fmt.Sprintf("%s-%06d", cate.LetterName, index), nil

}

func searchBillTypeById(ctx *ApiSession, collectName string, id primitive.ObjectID) (string, error) {
	fmt.Println(id.Hex())
	found, curbill := repo.RepoSeachDocMap(ctx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: collectName,
		Project:     []string{"type"},
		Query:       repo.Map{"_id": id},
		Sort:        bson.M{"_id": -1},
	})
	if !found {
		return "", fmt.Errorf("未找到该类型")
	}
	return curbill["type"].(string), nil
}

func excelToPdf(formBody *bytes.Buffer, pdfHost string) (*http.Response, error) {
	httpClient := &http.Client{
		Timeout: time.Duration(15) * time.Second,
	}
	client := &gotenberg.Client{Hostname: pdfHost, HTTPClient: httpClient}
	// 'merge="true"' \
	// --form 'pdfFormat="PDF/A-1a"' \
	// formData := url.Values{
	// 	"merge":     {"true"},
	// 	"pdfFormat": {"PDF/A-1a"},
	// }

	// 构建请求体
	// reqData := bytes.NewBufferString(formData.Encode())
	// reqData.WriteTo(formBody)
	doc, err := gotenberg.NewDocumentFromBytes("foo.xlsx", formBody.Bytes())

	if err != nil {
		fmt.Println(" to pdf read data err:", err)
		return nil, err
	}

	req := gotenberg.NewOfficeRequest(doc)

	req.Landscape(true)
	return client.Post(req)

}

func isManager(roles []string) bool {
	if len(roles) > 0 {
		for _, role := range roles {
			if role == "manager" {
				return true
			}
		}
	}
	return false
}
func isSender(roles []string) bool {
	if len(roles) > 0 {
		for _, role := range roles {
			if role == "sender" {
				return true
			}
		}
	}
	return false
}
func getUserById(apictx *ApiSession, id primitive.ObjectID) (*model.UserSmaple, error) {
	user := &model.UserSmaple{}
	_, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		Db:          "box-user",
		CollectName: repo.CollectionUsers,
		Query:       repo.Map{"_id": id},
		Project:     []string{"name", "avatar", "city", "loginName", "roles", "phone"},
	}, user)
	return user, err
}

// 获取一天的起始终止时间
// func getDayRange(t time.Time) (start, end time.Time) {
// 	loc, _ := time.LoadLocation("Local")
// 	date := t.Format("2006-01-02")
// 	startDate := date + " 00:00:00"
// 	startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", startDate, loc)
// 	endDate := date + " 23:59:59"
// 	endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endDate, loc)
// 	return startTime, endTime
// }

// 获取时间跨度的起始终止时间
// startDate/endDate 2023-01-31
func getTimeRange(startDate, endDate string) (start, end time.Time) {
	loc, _ := time.LoadLocation("Local")
	startDateTime := startDate + " 00:00:00"
	endDateTime := endDate + " 23:59:59"
	start, _ = time.ParseInLocation("2006-01-02 15:04:05", startDateTime, loc)
	end, _ = time.ParseInLocation("2006-01-02 15:04:05", endDateTime, loc)
	return
}

// 处理报表query条件
func handleReportQuery(query map[string]interface{}) map[string]interface{} {
	// 条件处理
	query["status"] = "complete"
	if _supplierId, ok := query["supplierId"]; ok {
		delete(query, "supplierId")
		supplierId, _ := primitive.ObjectIDFromHex(_supplierId.(string))
		if !supplierId.IsZero() {
			query["supplierId"] = supplierId

		}
	}

	if _timeRange, ok := query["timeRange"]; ok {
		timeRange, _ := _timeRange.([]interface{})

		if len(timeRange) == 2 {
			start, end := getTimeRange(timeRange[0].(string), timeRange[1].(string))
			query["completeTime"] = bson.M{"$gte": start, "$lte": end}
		}
		delete(query, "timeRange")
	}

	if _planIds, ok := query["planIds"]; ok {
		if len(_planIds.([]interface{})) > 0 {
			planQuery := bson.A{}
			for _, _planId := range _planIds.([]interface{}) {
				planId, _ := primitive.ObjectIDFromHex(_planId.(string))
				planQuery = append(planQuery, bson.M{"planId": planId})
			}
			query["$or"] = planQuery
		}
		delete(query, "planIds")
	}
	return query

}

// 获取公司名字
func getCompanyName(apictx *ApiSession) string {
	companyName := "中鱼互动"
	info := model.Setting{}
	found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
		CollectName: "infos",
	}, &info)

	if found {
		if info.CompanyName != "" {
			companyName = info.CompanyName
		}
	}
	return companyName
}

const (
	letterIdBits = 6
	letterIdMask = 1<<letterIdBits - 1
	letterIdMax  = 63 / letterIdBits
	letters      = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
)

var src = rand.NewSource(time.Now().UnixNano())

func randName(n int) string {
	b := make([]byte, n)
	for i, cache, remain := n-1, src.Int63(), letterIdMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdMax
		}
		if idx := int(cache & letterIdMask); idx < len(letters) {
			b[i] = letters[idx]
			i--
		}
		cache >>= letterIdBits
		remain--
	}
	return *(*string)(unsafe.Pointer(&b))
}