package models

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"go-admin/app/admin/models/tools"
	orm "go-admin/common/global"
	"go-admin/logger"
	tool "go-admin/tools"
	"gorm.io/gorm"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode"
	"unicode/utf8"
)

type CategoryExcel struct {
	FirstCategory  string `json:"first_category" binding:"required"` // 一级分类
	SecondCategory string `json:"second_category"`                   // 二级分类
	ThreeCategory  string `json:"three_category"`                    // 三级分类
}

type CommodityExcel struct {
	Category       string `json:"category" binding:"required"`         // 商品所属分类
	Name           string `json:"name"  binding:"required"`            // 商品名称
	ErpBarcode     string `json:"erp_barcode"`                         // 商品条码
	IMEIType       string `json:"imei_type" binding:"required"`        // 是否串码 1-无串码 2-串码（系统生成） 3-串码（手动添加）
	SysGenerate    string `json:"sys_generate" binding:"required"`     // 系统生成串码
	SupplierName   string `json:"supplier_name" binding:"required"`    // 供应商名称
	SellBrokerage  string `json:"sell_brokerage" binding:"required"`   // 销售毛利提成
	StaffBrokerage string `json:"staff_brokerage" binding:"required"`  // 员工毛利提成
	MemberDiscount string `json:"member_discount" binding:"required"`  // 会员优惠
	RetailPrice    string `json:"retail_price" binding:"required"`     // 指导零售价
	MinRetailPrice string `json:"min_retail_price" binding:"required"` // 最低零售价
	WholesalePrice string `json:"wholesale_price" binding:"required"`  // 指导采购价
	StaffCostPrice string `json:"staff_cost_price" binding:"required"` // 员工成本价加价
	Origin         string `json:"origin"`                              // 产地
	Remark         string `json:"remark"`                              // 备注
}

type StockExcel struct {
	Name           string `json:"name"`                                // 商品名称
	SerialNum      string `json:"serial_num"`                          // 商品编号
	StoreName      string `json:"store_name"  binding:"required"`      // 所属门店
	SysGenerate    string `json:"sys_generate"`                        // 系统生成串码
	WholesalePrice string `json:"wholesale_price" binding:"required"`  // 指导采购价
	StaffCostPrice string `json:"staff_cost_price" binding:"required"` // 员工成本价=员工成本价加价+指导采购价
	SupplierName   string `json:"supplier_name" binding:"required"`    // 供应商名称
	StockTime      string `json:"stock_time"`                          // 入库时间
	Count          string `json:"count" binding:"required"`            // 数量
}

type OrderExcel struct {
	SerialNum   string `json:"serial_num"`                     // 商品编号
	Name        string `json:"name"`                           // 商品名称
	IMEI        string `json:"imei"`                           // 商品串码
	Count       string `json:"count" binding:"required"`       // 销售数量
	StoreName   string `json:"store_name"  binding:"required"` // 所属门店
	SalePrice   string `json:"sale_price"`                     // 零售价
	PresentType string `json:"present_type"`                   // 是否赠送
	Remark      string `json:"remark"`                         // 备注
}

// 获取struct的tag标签，匹配excel导入数据
func getJSONTagNames(s interface{}) []string {
	valueType := reflect.TypeOf(s)
	if valueType.Kind() != reflect.Struct {
		fmt.Println("传入的不是结构体")
		return nil
	}

	var tagNames []string
	for i := 0; i < valueType.NumField(); i++ {
		field := valueType.Field(i)
		tag := field.Tag.Get("json")
		if tag != "" {
			tagNames = append(tagNames, tag)
		}
	}

	return tagNames
}

// FileExcelReader 预览excel数据（不做必填项校验）
func FileExcelReader(d []byte, cols []string) ([]byte, []map[string]interface{}, error) {
	reader, err := excelize.OpenReader(bytes.NewReader(d))
	if err != nil {
		return nil, nil, fmt.Errorf("open reader error: %v", err)
	}

	sheetList := reader.GetSheetList()
	if len(sheetList) == 0 {
		return nil, nil, errors.New("sheet list is empty")
	}

	rows, err := reader.Rows(sheetList[0])
	if err != nil {
		return nil, nil, fmt.Errorf("reader rows error: %v", err)
	}

	sheetCols, err := reader.GetCols(sheetList[0])
	if err != nil {
		return nil, nil, fmt.Errorf("reader get cols error: %v", err)
	}
	if len(sheetCols) == 0 {
		return nil, nil, errors.New("get cols is empty")
	}

	var colsMap []map[string]interface{}
	if len(cols) == 0 {
		switch sheetList[0] {
		case "导分类":
			cols = getJSONTagNames(CategoryExcel{})
		case "导商品":
			cols = getJSONTagNames(CommodityExcel{})
		case "导库存":
			cols = getJSONTagNames(StockExcel{})
		default:
			cols = make([]string, len(sheetCols))
			for i := range sheetCols {
				cols[i] = fmt.Sprintf("c%02d", i)
			}
		}
	} else if len(cols) != len(sheetCols) {
		return nil, nil, errors.New("cols length does not match the number of columns")
	}

	for rows.Next() {
		columns, err := rows.Columns()
		if err != nil {
			return nil, nil, fmt.Errorf("rows columns error: %v", err)
		}

		columnMap := make(map[string]interface{}, len(cols))
		for i, col := range cols {
			if i < len(columns) {
				columnMap[col] = columns[i]
			} else {
				columnMap[col] = ""
			}
		}

		logger.Info("columnMap:", logger.Field("columnMap", columnMap))
		colsMap = append(colsMap, columnMap)
	}

	logger.Info("colsMap:", logger.Field("colsMap", colsMap))
	mCols, err := json.Marshal(colsMap)
	if err != nil {
		return mCols, nil, fmt.Errorf("marshal error: %v", err)
	}

	return mCols, colsMap, nil
}

// FileExcelImport 导入excel数据（校验必填项）
func FileExcelImport(c *gin.Context, d []byte, cols []string, nType, storeId int) ([]byte, []map[string]interface{}, error) {
	reader, err := excelize.OpenReader(bytes.NewReader(d))
	if err != nil {
		return nil, nil, fmt.Errorf("open reader error: %v", err)
	}

	sheetList := reader.GetSheetList()
	if len(sheetList) == 0 {
		return nil, nil, errors.New("sheet list is empty")
	}

	rowData, err := reader.GetRows(sheetList[0])
	if err != nil {
		return nil, nil, fmt.Errorf("reader rows error: %v", err)
	}

	rows, err := reader.Rows(sheetList[0])
	if err != nil {
		return nil, nil, fmt.Errorf("reader rows err: %v", err)
	}

	sheetCols, err := reader.GetCols(sheetList[0])
	if err != nil {
		return nil, nil, fmt.Errorf("reader get cols err: %v", err)
	}

	if len(sheetCols) == 0 {
		return nil, nil, errors.New("get cols is empty")
	}

	sheetCols = checkExcelFormat(rowData, sheetCols)

	var colsMap []map[string]interface{}
	if len(cols) == 0 {
		switch nType { // 导入类型：1 商品分类  2 商品资料  3 商品库存
		case 1:
			if sheetList[0] != "导分类" {
				return nil, nil, errors.New("格式错误，不是分类模版excel")
			}
			if err := checkCategoryExcel(sheetCols); err != nil {
				return nil, nil, err
			}
			cols = getJSONTagNames(CategoryExcel{})
		case 2:
			if sheetList[0] != "导商品" {
				return nil, nil, errors.New("格式错误，不是商品模版excel")
			}
			if err := checkCommodityExcel(sheetCols); err != nil {
				return nil, nil, err
			}
			cols = getJSONTagNames(CommodityExcel{})
		case 3:
			if sheetList[0] != "导库存" {
				return nil, nil, errors.New("格式错误，不是库存模版excel")
			}
			if err := checkStockExcel(sheetCols); err != nil {
				return nil, nil, err
			}
			cols = getJSONTagNames(StockExcel{})
		case 4:
			if sheetList[0] != "导零售" {
				return nil, nil, errors.New("格式错误，不是零售模版excel")
			}
			if err := checkOrderExcel(c, sheetCols, storeId); err != nil {
				return nil, nil, err
			}
			cols = getJSONTagNames(OrderExcel{})
		default:
			return nil, nil, errors.New("格式错误，不是商品分类或资料模版excel")
		}
	} else if len(cols) != len(sheetCols) {
		return nil, nil, errors.New("cols length does not match the number of columns")
	}

	nCounter := len(rowData) //记录有数据的行数，空行则跳过循环
	for rows.Next() {
		if nCounter == 0 {
			break
		}
		nCounter--
		columns, err := rows.Columns()
		if err != nil {
			return nil, nil, fmt.Errorf("rows columns err: %v", err)
		}

		columnMap := make(map[string]interface{}, len(cols))
		for i, col := range cols {
			if i < len(columns) {
				columnMap[col] = columns[i]
			} else {
				columnMap[col] = ""
			}
		}

		logger.Info("columnMap:", logger.Field("columnMap", columnMap))
		colsMap = append(colsMap, columnMap)
	}

	logger.Info("colsMap:", logger.Field("colsMap", colsMap))
	mCols, err := json.Marshal(colsMap)
	if err != nil {
		return mCols, nil, fmt.Errorf("marshal err: %v", err)
	}

	return mCols, colsMap, nil
}

// checkExcelFormat校验excel表格格式，剔除最后1行的空格
func checkExcelFormat(rowData, sheetCols [][]string) [][]string {
	if findMaxLength(sheetCols) > len(rowData) { // 最后1行有空格，踢除
		newSheetCols := make([][]string, len(sheetCols))
		for i, col := range sheetCols {
			if len(col) > len(rowData) {
				newSheetCols[i] = col[:len(rowData)]
			} else {
				newSheetCols[i] = col
			}
		}
		return newSheetCols
	}

	return sheetCols
}

// 校验商品分类导入规则
// 导入商品分类校验报错： （1）只有3级，没有2级或1级 （2）有2，3级，但没有1级
func checkCategoryExcel(sheetCols [][]string) error {
	if len(sheetCols) != 3 {
		return errors.New("模版错误，请检查文件")
	}

	if len(sheetCols[0]) < len(sheetCols[1]) || len(sheetCols[0]) < len(sheetCols[2]) {
		return errors.New("格式错误，缺少一级分类")
	} else if len(sheetCols[1]) < len(sheetCols[2]) {
		return errors.New("格式错误，缺少二级分类")
	}

	for i := 1; i < len(sheetCols[2]); i++ {
		if sheetCols[0][i] == "" && (sheetCols[1][i] != "" || sheetCols[2][i] != "") {
			return errors.New("格式错误，缺少一级分类")
		} else if sheetCols[2][i] != "" && sheetCols[1][i] == "" {
			return errors.New("格式错误，缺少二级分类")
		}
	}

	if duplicateName, nFlag := hasDuplicateNames(sheetCols); nFlag {
		return fmt.Errorf("分类名称不允许重复，请检查:[%v]", duplicateName)
	}

	return nil
}

//// 校验名称是否相同，有则false
//func hasDuplicateNames(sheetCols [][]string) (string, bool) {
//	nameMap := make(map[string]struct{})
//
//	for _, col := range sheetCols {
//		for _, name := range col {
//			if _, exists := nameMap[name]; exists && name != "" {
//				// 有重复的名称
//				return name, true
//			}
//			nameMap[name] = struct{}{}
//		}
//	}
//	// 没有重复的名称
//	return "", false
//}

//// 校验名称是否相同，有则返回true和重复的名称，备注：只能校验不同的列中不能有重复数据，如：第一列的123，第二列不能有123
//func hasDuplicateNames(sheetCols [][]string) (string, bool) {
//	globalMap := make(map[string]struct{})
//
//	for _, col := range sheetCols {
//		colMap := make(map[string]struct{})
//		for _, name := range col {
//			// 忽略空名称
//			if name == "" {
//				continue
//			}
//
//			// 检查全局map中是否已存在
//			if _, exists := globalMap[name]; exists {
//				return name, true
//			}
//
//			// 将名称添加到当前列map中
//			colMap[name] = struct{}{}
//		}
//
//		// 将当前列map中的元素添加到全局map中
//		for name := range colMap {
//			globalMap[name] = struct{}{}
//		}
//	}
//
//	// 没有重复的名称
//	return "", false
//}

// 校验名称是否相同，有则返回true和重复的名称
// 第二列数据如果重复，需要看第一列同一行的数据是否相同，如果不同则报错。
// 第三列数据不能有重复的名称
func hasDuplicateNames(sheetCols [][]string) (string, bool) {
	//firstColMap := make(map[string]bool)
	secondColMap := make(map[string]string) // Map记录第二列数据的重复情况，以及对应第一列的数据
	thirdColMap := make(map[string]bool)

	// 确保每一列数据都有相同数量的行数
	rowsCount := len(sheetCols[0])
	//for i, col := range sheetCols {
	//	if len(col) != rowsCount && i != 2 {
	//		return "每列数据的行数不一致", true
	//	}
	//}

	for i := 0; i < rowsCount; i++ {
		//// 检查第一列
		//firstColName := sheetCols[0][i]
		//if firstColName != "" {
		//	if _, exists := firstColMap[firstColName]; exists {
		//		return firstColName, true
		//	}
		//	firstColMap[firstColName] = true
		//}

		// 检查第二列
		if len(sheetCols[1]) < i+1 {
			continue
		}
		secondColName := sheetCols[1][i]
		if secondColName != "" {
			if firstCol, exists := secondColMap[secondColName]; exists && firstCol != sheetCols[0][i] {
				return secondColName, true
			}
			secondColMap[secondColName] = sheetCols[0][i]
		}

		// 检查第三列
		if len(sheetCols[2]) < i+1 {
			continue
		}
		thirdColName := sheetCols[2][i]
		if thirdColName != "" {
			if _, exists := thirdColMap[thirdColName]; exists {
				return thirdColName, true
			}
			thirdColMap[thirdColName] = true
		}
	}

	// 没有重复的名称
	return "", false
}

// 校验商品资料导入规则
// 导入商品资料校验报错：必填项缺少数据（除了产地、备注，其他都是必填项）
func checkCommodityExcel(sheetCols [][]string) error {
	if len(sheetCols) != 15 {
		return errors.New("模版错误，请检查文件")
	}

	for i := 0; i < len(sheetCols)-2; i++ {
		if i == 2 {
			continue
		}
		if len(sheetCols[i]) < len(sheetCols[i+1]) {
			return errors.New("格式错误，有必填项未录入")
		}
		for _, v := range sheetCols[i] {
			if v == "" {
				return errors.New("格式错误，有必填项未录入")
			}
		}
	}
	return nil
}

// 校验库存导入规则
// 导入规则:
// (1)商品名称：100 字符内，商品名称和商品编号可只填一项，同时填写时优先按照商品名称导库存；
// 且需为已有商品名称，否则红框展示，下方红字提示“该商品不存在，请新建商品”
// (2)商品编号：限纯数字，商品名称和商品编号可只填一项，同时填写时优先按照商品名称导库存；
// 且需为已有商品编号，否则红框展示，下方红字提示“该商品编号不存在”
// (3)所属门店：必填项，100 字符内；且需为已有门店，否则红框展示，下方红字提示“该门店不存在，请新建门店”

// (4)商品串码：100 字符内，限制仅可填数字或英文；串码类必填，非串码不填
// 如果是串码类商品没填串码或者填了中文，红框展示，下方红字提示“串码类商品，请填写正确地串码”
// 如果是非串码商品，填了串码，红框展示，下方红字提示“非串码商品，无需填写串码”
// 备注：库存导入时，如果是串码商品都需填写串码才能导入，不区分是否自动生成串码；自动生成是在后续采购导入时使用；2023/12/19跟产品核实

// (5)采购价：必填项，入库时的采购价，限＞0 数字
// (6)员工成本价：必填项，入库时的员工成本价，限＞0 数字
// (7)供应商：必填项，100 字符内，且需为已有供应商，否则红框展示，下方红字提示“该供应商不存在，请新建供应商”
// (8)入库时间：非必填项，含年月日，填写后入库时间会按照填写的日期0点展示，不填写则按照实际导入成功时间展示

// (9)数量：必填项，限制≥1正整数，
// 串码类商品需拆分成每个数量为1单独导入，
// 非串码可大于1直接导入 * 串码类商品如数量填写＞1，红框展示，下方红字提示“串码类商品数量只能为1”

// （10）入库时间：必须早于/小于当前时间
func checkStockExcel(sheetCols [][]string) error {
	if len(sheetCols) != 9 {
		return errors.New("模版错误，请检查文件")
	}

	maxLength := findMaxLength(sheetCols)
	nLow, nMax := determineLowAndMax(sheetCols)

	if nMax < maxLength {
		return errors.New("第" + strconv.Itoa(nMax+1) + "行商品名称和商品编号不能同时为空")
	}

	// 判断是否有重复串码
	if duplicateName, nFlag := hasDuplicateIMEI(sheetCols[3]); nFlag {
		return fmt.Errorf("商品串码不允许重复，请检查:[%v]", duplicateName)
	}

	//先遍历第1列
	for i := 1; i < nLow; i++ {
		if sheetCols[0][i] == "" && sheetCols[1][i] == "" { // 商品名称和编号不能都为空
			return errors.New("第" + strconv.Itoa(i+1) + "行商品名称和商品编号不能同时为空")
		}
	}

	for i := 1; i < nMax; i++ { // todo
		if i < len(sheetCols[0]) {
			if !IsExistingProduct(sheetCols[0][i]) {
				return errors.New("第" + strconv.Itoa(i+1) + "行商品不存在，请新建商品")
			}
		}

		if i < len(sheetCols[1]) {
			// 商品编号必须为纯数字
			if sheetCols[1][i] != "" {
				if _, err := strconv.Atoi(sheetCols[1][i]); err != nil {
					return errors.New("第" + strconv.Itoa(i+1) + "行商品编号必须为纯数字")
				}
			}

			if !isExistingProductCode(sheetCols[1][i]) {
				return errors.New("第" + strconv.Itoa(i+1) + "行商品编号不存在")
			}
		}

		// 所属门店不能为空
		if i < len(sheetCols[2]) {
			if sheetCols[2][i] == "" {
				return errors.New("第" + strconv.Itoa(i+1) + "行所属门店不能为空")
			}
			if !isExistingStore(sheetCols[2][i]) {
				return errors.New("第" + strconv.Itoa(i+1) + "行门店不存在，请新建门店")
			}
		}

		// 商品串码规则校验 当串码行数跟其他一致时正常遍历，如果小于其他行，则最后一行不遍历 todo
		// 如串码在商品库存表已经存在，则报错提示
		//if len(sheetCols[3]) <= nLow && i+1 < nLow {
		if i < len(sheetCols[3]) {
			productName := ""
			if i < len(sheetCols[0]) {
				productName = sheetCols[0][i]
			}

			productCode := ""
			if i < len(sheetCols[1]) {
				productCode = sheetCols[1][i]
			}

			count := ""
			if i < len(sheetCols[8]) {
				count = sheetCols[8][i]
			}

			if err := checkSerialCode(productName, productCode, sheetCols[3][i], i); err != nil {
				return err
			}
			// 串码类商品数量只能为1
			if sheetCols[3][i] != "" && count != "1" {
				return errors.New("第" + strconv.Itoa(i+1) + "行串码类商品数量只能为1")
			}
		}

		//// 采购价、员工成本价必须大于0
		//if i < len(sheetCols[4]) {
		//	if purchasePrice, err := strconv.ParseFloat(sheetCols[4][i], 64); err != nil || purchasePrice <= 0 {
		//		return errors.New("第" + strconv.Itoa(i+1) + "行采购价必须是大于0的数字")
		//	}
		//}

		//if i < len(sheetCols[5]) {
		//	if employeeCost, err := strconv.ParseFloat(sheetCols[5][i], 64); err != nil || employeeCost <= 0 {
		//		return errors.New("第" + strconv.Itoa(i+1) + "行员工成本价必须是大于0的数字")
		//	}
		//}

		// 供应商不能为空
		if i < len(sheetCols[6]) {
			if sheetCols[6][i] == "" {
				return errors.New("第" + strconv.Itoa(i+1) + "行供应商不能为空")
			}
			if !isExistingSupplier(sheetCols[6][i]) {
				return errors.New("第" + strconv.Itoa(i+1) + "行供应商不存在，请新建供应商")
			}
		}

		// 入库时间格式校验
		//if len(sheetCols[7]) < nLow && i+1 < nLow {
		if i < len(sheetCols[7]) {
			if sheetCols[7][i] != "" {
				parsedTime, err := time.Parse("2006/1/2", sheetCols[7][i])
				if err != nil {
					return errors.New("第" + strconv.Itoa(i+1) + "行入库时间格式错误，请设置单元格格式为日期：YYYY/MM/DD")
				}
				// 格式化时间为指定格式
				formattedTime := parsedTime.Format(DateTimeFormat)
				//sheetCols[7][i] = formattedTime + "00-00-00"

				// 需小于当前时间
				nFlag, _ := isInputTimeBeforeOrEqualNow(formattedTime)
				if !nFlag {
					return errors.New("第" + strconv.Itoa(i+1) + "行入库时间不能晚于当前时间")
				}

			}
		}

		// 数量必须为正整数
		if i < len(sheetCols[8]) {
			if quantity, err := strconv.Atoi(sheetCols[8][i]); err != nil || quantity < 1 {
				return errors.New("第" + strconv.Itoa(i+1) + "行数量必须是大于等于1的整数")
			}
		}
	}

	return nil
}

// 判断是否早于等于当前时间
func isInputTimeBeforeOrEqualNow(inputTimeString string) (bool, error) {
	// 将输入时间字符串解析为 time.Time 类型
	inputTime, _ := time.Parse(time.RFC3339, inputTimeString)

	// 获取当前时间
	currentTime := time.Now()

	// 比较时间
	isBeforeOrEqual := inputTime.After(currentTime)

	return !isBeforeOrEqual, nil
}

// 校验第5列门店名称是否相同
func hasDuplicateStore(sheetCols [][]string) (string, bool) {
	storeMap := make(map[string]struct{})
	var storeName string

	for row := 1; row < len(sheetCols[4]); row++ {
		// 获取当前行的门店名称
		currentStore := sheetCols[4][row] // 第5列门店名称

		if currentStore == "" {
			continue // 如果门店名称为空，跳过该行
		}

		// 如果这是第一次遇到门店名称，记录下来
		if storeName == "" {
			storeName = currentStore
		}

		// 检查当前门店名称是否与之前的名称一致
		if currentStore != storeName {
			// 找到不一致的门店名称，返回不一致的门店名称和标记为true
			return currentStore, true
		}

		// 存储门店名称
		storeMap[currentStore] = struct{}{}
	}

	// 如果没有发现不一致的门店名称，返回空字符串和false
	return "", false
}

// 校验串码是否相同，有则false
func hasDuplicateIMEI(sheetCols []string) (string, bool) {
	nameMap := make(map[string]struct{})

	for _, name := range sheetCols {
		if _, exists := nameMap[name]; exists && name != "" {
			// 有重复的名称
			return name, true
		}
		nameMap[name] = struct{}{}
	}
	// 没有重复的名称
	return "", false
}

func findMaxLength(sheetCols [][]string) int {
	maxLength := 0
	for _, col := range sheetCols {
		if len(col) > maxLength {
			maxLength = len(col)
		}
	}
	return maxLength
}

func determineLowAndMax(sheetCols [][]string) (int, int) {
	nLow := len(sheetCols[0])
	nMax := len(sheetCols[1])
	if len(sheetCols[0]) >= len(sheetCols[1]) {
		nLow = len(sheetCols[1])
		nMax = len(sheetCols[0])
	}
	return nLow, nMax
}

// IsExistingProduct 查询商品资料中某个名称的商品是否存在
func IsExistingProduct(productName string) bool {
	if productName == "" {
		return true
	}
	// 实现商品名称是否存在的逻辑
	var count int64
	orm.Eloquent.Debug().Model(&ErpCommodity{}).
		Where("name = ?", productName).
		Count(&count)

	return count > 0
}

func isExistingProductCode(productCode string) bool {
	if productCode == "" {
		return true
	}
	// 实现商品编号是否存在的逻辑
	var count int64
	orm.Eloquent.Debug().Model(&ErpCommodity{}).
		Where("serial_number = ?", productCode).
		Count(&count)

	return count > 0
}

func isExistingStore(storeName string) bool {
	// 实现门店是否存在的逻辑
	var count int64
	orm.Eloquent.Debug().Model(&Store{}).
		Where("name = ?", storeName).
		Count(&count)

	return count > 0
}

func IsExistingStoreById(storeId int) bool {
	// 实现门店是否存在的逻辑
	var count int64
	orm.Eloquent.Debug().Model(&Store{}).
		Where("id = ?", storeId).
		Count(&count)

	return count > 0
}

func isExistingSupplier(supplierName string) bool {
	// 实现供应商是否存在的逻辑
	var count int64
	orm.Eloquent.Debug().Model(&ErpSupplier{}).
		Where("name = ?", supplierName).
		Count(&count)

	return count > 0
}

func checkSerialCode(productName, productCode, serialCode string, row int) error {
	var existingCommodity ErpCommodity
	var existingStockCommodity ErpStockCommodity
	var queryCondition string

	if productCode != "" {
		queryCondition = "serial_number= ?"
	} else if productName != "" {
		queryCondition = "name = ?"
	} else {
		return errors.New("商品名称和商品编码不能都为空")
	}

	result := orm.Eloquent.Where(queryCondition, productName).Or(queryCondition, productCode).First(&existingCommodity)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return errors.New("未查询到商品数据")
		}
		fmt.Println("Error:", result.Error)
		return result.Error
	}

	nIMEIType := int(existingCommodity.IMEIType)

	if nIMEIType == 1 && serialCode != "" {
		return errors.New("非串码商品，无需填写串码")
	}

	//if nIMEIType == 2 && serialCode != ""{
	//	return errors.New("第" + strconv.Itoa(row+1) + "行串码无需填写，该商品串码系统自动生成")
	//}

	if (nIMEIType == 2 || nIMEIType == 3) && serialCode == "" {
		return errors.New("第" + strconv.Itoa(row+1) + "行是串码类商品，请填写正确地串码")
	}

	if nIMEIType != 1 && !isNumericOrAlpha(serialCode) {
		return errors.New("串码类商品，请填写正确的串码")
	}

	if nIMEIType != NoIMEICommodity { // 串码商品才进行判断
		result = orm.Eloquent.Where("imei = ?", serialCode).First(&existingStockCommodity)
		if result.Error != nil {
			if errors.Is(result.Error, gorm.ErrRecordNotFound) { //没找到对应串码
				return nil
			}
			fmt.Println("Error:", result.Error)
			return result.Error
		}

		return errors.New("第" + strconv.Itoa(row+1) + "行串码重复，请勿重复导入")
	}

	return nil
}

//func isNumericOrAlpha(s string) bool {
//	for _, char := range s {
//		if !unicode.IsDigit(char) && !unicode.IsLetter(char) {
//			return false
//		}
//	}
//	return true
//}

func isNumericOrAlpha(s string) bool {
	if utf8.RuneCountInString(s) > 100 {
		return false // 字符串超过100字符，返回 false
	}

	for _, char := range s {
		if unicode.Is(unicode.Scripts["Han"], char) {
			return false // 包含中文，返回 false
		}
	}
	return true // 不包含中文且长度满足条件，返回 true
}

// 将读取的excel数据转换成CategoryExcel struct
func transCategoryData(colsMap []map[string]interface{}) []CategoryExcel {
	var categories []CategoryExcel

	// 遍历 colsMap 进行类型断言和转换
	for _, col := range colsMap {
		var category CategoryExcel

		for key, value := range col {
			switch key {
			case "first_category":
				if name, ok := value.(string); ok {
					category.FirstCategory = name
				}
			case "second_category":
				if name, ok := value.(string); ok {
					category.SecondCategory = name
				}
			case "three_category":
				if name, ok := value.(string); ok {
					category.ThreeCategory = name
				}
			}
		}

		// 将处理后的数据追加到 categories 中
		categories = append(categories, category)
	}

	return categories
}

// ImportCategoryData 导入商品分类到数据库
// 规则：分类只有3级，所有分类不允许名称完全相同
func ImportCategoryData(colsMap []map[string]interface{}, businessId uint32) error {
	data := transCategoryData(colsMap)

	if duplicateName, nFlag := hasDuplicateInDb(data); nFlag {
		return fmt.Errorf("数据库已有此分类名称，不允许重复，请检查:[%v]", duplicateName)
	}

	for _, item := range data {
		var firstCategory, secondCategory, threeCategory Category
		if item.FirstCategory == "" { // 一级分类名称为空则跳过，继续遍历
			continue
		}

		// 插入或获取一级分类
		err := orm.Eloquent.Debug().Table("erp_category").Where("name = ? and pid = ? and display = ? "+
			"and cooperative_business_id = ?", item.FirstCategory, 0, 1, businessId).
			First(&firstCategory).Error
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				firstCategory.Name = item.FirstCategory
				firstCategory.Pid = 0
				firstCategory.Display = 1
				firstCategory.CooperativeBusinessId = businessId
				firstCategory.ID = 0
				// 如果没有符合条件的记录，则创建新记录
				err = orm.Eloquent.Debug().Create(&firstCategory).Error
				if err != nil {
					return err
				}
			} else {
				return err
			}
		}

		// 插入或获取二级分类
		if item.SecondCategory != "" {
			err = orm.Eloquent.Debug().FirstOrCreate(&secondCategory,
				Category{
					Name:                  item.SecondCategory,
					Pid:                   firstCategory.ID,
					Display:               1,
					CooperativeBusinessId: businessId,
				}).Error
			if err != nil {
				return err
			}

		}

		// 插入三级分类
		if item.ThreeCategory != "" {
			err = orm.Eloquent.Debug().FirstOrCreate(&threeCategory,
				Category{
					Name:                  item.ThreeCategory,
					Pid:                   secondCategory.ID,
					Display:               1,
					CooperativeBusinessId: businessId,
				}).Error
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// 判断是否存在重复数据
func hasDuplicateInDb(data []CategoryExcel) (string, bool) {
	for _, item := range data {
		// 判断是导入几级分类
		nType := 0
		if item.ThreeCategory != "" && item.SecondCategory != "" && item.FirstCategory != "" {
			nType = 3
		} else if item.ThreeCategory == "" && item.SecondCategory != "" && item.FirstCategory != "" {
			nType = 2
		} else if item.ThreeCategory == "" && item.SecondCategory == "" && item.FirstCategory != "" {
			nType = 1
		} else {
			return "", true
		}

		switch nType {
		case 1: // 导入一级分类
			if exists := isCategoryExists(item.FirstCategory); exists {
				return item.FirstCategory, true
			}
		case 2: // 导入二级分类：查看二级分类名称是否重复；查询一级分类名称跟二/三级分类是否重复
			if exists := isFirstCategoryDuplicate(item.FirstCategory); exists {
				return item.FirstCategory, true
			}
			if exists := isCategoryExists(item.SecondCategory); exists {
				return item.SecondCategory, true
			}
		case 3: // 导入三级分类：查看三级分类名称是否重复；查询一级分类名称跟二/三级分类是否重复，查询二级分类跟一，三级是否重复
			if exists := isFirstCategoryDuplicate(item.FirstCategory); exists {
				return item.FirstCategory, true
			}
			if exists := isSecondCategoryDuplicate(item.SecondCategory); exists {
				return item.SecondCategory, true
			}
			if exists := isCategoryExists(item.ThreeCategory); exists {
				return item.ThreeCategory, true
			}

			// 如果二级分类遍历后名称重复，则需判断其一级分类是否相同，如何相同则可以重复；否则不能重复
			if isSecondCategoryExists(item.SecondCategory) {
				if !isFirstCategoryExists(item.FirstCategory) {
					return item.SecondCategory, true
				}
			}
		}
	}

	return "", false
}

// 查询一级分类名称跟二/三级分类是否重复
func isFirstCategoryDuplicate(categoryName string) bool {
	var count int64
	orm.Eloquent.Debug().Model(&Category{}).
		Where("name = ? and pid != ?", categoryName, 0).
		Count(&count)

	return count > 0
}

// 查询一级分类名称是否重复
func isFirstCategoryExists(categoryName string) bool {
	var count int64
	orm.Eloquent.Debug().Model(&Category{}).
		Where("name = ? and pid = ?", categoryName, 0).
		Count(&count)

	return count > 0
}

// 查询二级分类跟一，三级是否重复
func isSecondCategoryDuplicate(categoryName string) bool {
	var count int64
	orm.Eloquent.Debug().Model(&Category{}).
		Where("name = ? and LENGTH(number) != ?", categoryName, 6).
		Count(&count)

	return count > 0
}

// 查询二级分类是否重复
func isSecondCategoryExists(categoryName string) bool {
	var count int64
	orm.Eloquent.Debug().Model(&Category{}).
		Where("name = ? and LENGTH(number) = ?", categoryName, 6).
		Count(&count)

	return count > 0
}

// 判断分类是否存在
func isCategoryExists(categoryName string) bool {
	var count int64
	orm.Eloquent.Debug().Model(&Category{}).
		Where("name = ?", categoryName).
		Count(&count)

	return count > 0
}

// ImportCommodityData 导入商品资料
func ImportCommodityData(colsMap []map[string]interface{}, businessId uint32) error {
	data, err := transCommodityData(colsMap)
	if err != nil {
		return err
	}

	var erpCommodities []ErpCommodity
	erpCommodities, err = convertToErpCommodities(data, businessId)
	if err != nil {
		return err
	}

	err = updateOrInsertCommodities(erpCommodities)
	if err != nil {
		return err
	}

	return nil
}

// 将读取的excel数据转换成CommodityExcel struct
func transCommodityData(colsMap []map[string]interface{}) ([]CommodityExcel, error) {
	var commodities []CommodityExcel

	// 遍历 colsMap 进行类型断言和转换
	for _, col := range colsMap {
		var commodity CommodityExcel

		// 将 col 转换为 JSON 字符串
		jsonData, err := json.Marshal(col)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal data to JSON: %v", err)
		}

		// 将 JSON 字符串反序列化为 CommodityExcel
		if err := json.Unmarshal(jsonData, &commodity); err != nil {
			return nil, fmt.Errorf("failed to unmarshal JSON to CommodityExcel: %v", err)
		}

		// 将处理后的数据追加到 commodities 中
		commodities = append(commodities, commodity)
	}

	return commodities, nil
}

// 将读取的excel数据转换成CommodityExcel struct
func transStockData(colsMap []map[string]interface{}) ([]StockExcel, error) {
	var stockInfos []StockExcel

	// 遍历 colsMap 进行类型断言和转换
	for _, col := range colsMap {
		var stockInfo StockExcel

		// 将 col 转换为 JSON 字符串
		jsonData, err := json.Marshal(col)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal data to JSON: %v", err)
		}

		// 将 JSON 字符串反序列化为 CommodityExcel
		if err := json.Unmarshal(jsonData, &stockInfo); err != nil {
			return nil, fmt.Errorf("failed to unmarshal JSON to StockExcel: %v", err)
		}

		// 将处理后的数据追加到 commodities 中
		stockInfos = append(stockInfos, stockInfo)
	}

	return stockInfos, nil
}

func convertToErpCommodities(data []CommodityExcel, businessId uint32) ([]ErpCommodity, error) {
	var erpCommodities []ErpCommodity

	productCounter := tools.NewProductCounter()
	for _, item := range data {
		category, err := getCategoryByName(item.Category)
		if err != nil {
			return nil, err
		}

		list, err := GetSupplier(&GetSupplierRequest{Name: item.SupplierName, CooperativeBusinessId: businessId})
		if len(list.List) == 0 || errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("[%v]该供应商不存在，请新建供应商", item.SupplierName)
		}

		barCode := ""
		if item.ErpBarcode != "" { // 条码不为空则校验
			barCode, err = CheckAndConvertBarcode(item.ErpBarcode)
			if err != nil {
				return nil, err
			}
		} else { // 条码为空则自动生成
			barCode, err = GenerateBarcode(category.ID)
			if err != nil {
				return nil, err
			}
		}

		serialNumber := fmt.Sprintf("%s%04d", category.Number,
			getNumberOnCategory(category.ID)+int64(productCounter.GetNextProductNumber(category.Number)))
		fmt.Println("商品编号:", serialNumber)

		erpCommodity, err := convertToErpCommodity(item, category, &list.List[0], serialNumber, barCode)
		if err != nil {
			return nil, err
		}

		erpCommodities = append(erpCommodities, erpCommodity)
	}

	return erpCommodities, nil
}

// 查询商品分类
func getCategoryByName(name string) (*Category, error) {
	var category Category
	err := orm.Eloquent.Debug().Model(&Category{}).
		Where("name = ?", name).First(&category).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, fmt.Errorf("[%v]该分类不存在，请先新建分类", name)
	}
	return &category, err
}

// 转换格式，匹配Commodity的model
func convertToErpCommodity(item CommodityExcel, category *Category, supplier *Supplier, serialNumber, barCode string) (ErpCommodity, error) {
	brokerage1Float, err := strconv.ParseFloat(strings.TrimRight(item.SellBrokerage, "%"), 64) // 销售毛利
	if err != nil {
		return ErpCommodity{}, fmt.Errorf("销售毛利转换有误:[%v]", err)
	}
	brokerage2Float, err := strconv.ParseFloat(strings.TrimRight(item.StaffBrokerage, "%"), 64) // 员工毛利提成
	if err != nil {
		return ErpCommodity{}, fmt.Errorf("员工毛利提成转换有误:[%v]", err)
	}
	memberDiscountFloat, err := strconv.ParseFloat(item.MemberDiscount, 64) // 会员优惠
	if err != nil {
		return ErpCommodity{}, fmt.Errorf("会员优惠转换有误:[%v]", err)
	}
	nRetailPrice, err := strconv.ParseFloat(item.RetailPrice, 64) // 指导零售价
	if err != nil {
		return ErpCommodity{}, fmt.Errorf("指导零售价转换有误:[%v]", err)
	}
	nMinRetailPrice, err := strconv.ParseFloat(item.MinRetailPrice, 64) // 最低零售价
	if err != nil {
		return ErpCommodity{}, fmt.Errorf("最低零售价转换有误:[%v]", err)
	}
	nStaffCostPrice, err := strconv.ParseFloat(item.StaffCostPrice, 64) // 员工成本价加价
	if err != nil {
		return ErpCommodity{}, fmt.Errorf("员工成本价加价转换有误:[%v]", err)
	}
	nWholesalePrice, err := strconv.ParseFloat(item.WholesalePrice, 64) // 指导采购价
	if err != nil {
		return ErpCommodity{}, fmt.Errorf("指导采购价转换有误:[%v]", err)
	}

	//将是否串码转换为数字 1-无串码 2-串码（系统生成） 3-串码（手动添加）
	var nIMEIType uint32
	switch item.IMEIType {
	case "串码类":
		if item.SysGenerate == "是" {
			nIMEIType = 2
		} else if item.SysGenerate == "否" {
			nIMEIType = 3
		} else {
			return ErpCommodity{}, errors.New("[系统生成串码]列有非法字段")
		}
	case "非串码":
		nIMEIType = 1
	default:
		return ErpCommodity{}, errors.New("[是否串码]列有非法字段")
	}

	//serialNumber := fmt.Sprintf("%s%04d", category.Number, getNumberOnCategory(category.ID)+1)
	//fmt.Println("商品编号:", serialNumber)

	return ErpCommodity{
		SerialNumber:    serialNumber,
		Name:            item.Name,
		ErpCategoryId:   category.ID,
		ErpCategoryName: item.Category,
		ErpBarcode:      barCode,
		IMEIType:        nIMEIType,
		ErpSupplierId:   supplier.ID,
		ErpSupplierName: item.SupplierName,
		RetailPrice:     tool.RoundToTwoDecimalPlaces(nRetailPrice),
		MinRetailPrice:  tool.RoundToTwoDecimalPlaces(nMinRetailPrice),
		StaffCostPrice:  tool.RoundToTwoDecimalPlaces(nStaffCostPrice),
		WholesalePrice:  tool.RoundToTwoDecimalPlaces(nWholesalePrice),
		Brokerage1:      tool.RoundToTwoDecimalPlaces(brokerage1Float),
		Brokerage2:      tool.RoundToTwoDecimalPlaces(brokerage2Float),
		MemberDiscount:  tool.RoundToTwoDecimalPlaces(memberDiscountFloat),
		Origin:          item.Origin,
		Remark:          item.Remark,
	}, nil
}

// 操作数据库，通过商品名称查找，没有则插入，有则更新
func updateOrInsertCommodities(erpCommodities []ErpCommodity) error {
	for _, erpCommodity := range erpCommodities {
		var existingCommodity ErpCommodity
		result := orm.Eloquent.Where("name = ?", erpCommodity.Name).First(&existingCommodity)

		if result.Error != nil {
			if errors.Is(result.Error, gorm.ErrRecordNotFound) {
				orm.Eloquent.Create(&erpCommodity)
				fmt.Println("Inserted:", erpCommodity.Name)
			} else {
				fmt.Println("Error:", result.Error)
				return result.Error
			}
		} else {
			orm.Eloquent.Model(&existingCommodity).Updates(&erpCommodity)
			fmt.Println("Updated:", erpCommodity.Name)
		}
	}

	return nil
}

// 查询商品列表中同一类商品分类下商品的个数
func getNumberOnCategory(categoryId uint32) int64 {
	var count int64
	orm.Eloquent.Debug().Model(&ErpCommodity{}).
		Where("erp_category_id = ?", categoryId).
		Count(&count)

	return count
}

//// GenerateSerialNumber 生成商品编号（会有重复编码）
//func GenerateSerialNumber(categoryId uint32) (string, error) {
//	var category Category
//	err := orm.Eloquent.Debug().Model(&Category{}).
//		Where("id = ?", categoryId).First(&category).Error
//	if errors.Is(err, gorm.ErrRecordNotFound) {
//		return "", errors.New("未查到商品分类")
//	}
//
//	var count int64
//	orm.Eloquent.Debug().Model(&ErpCommodity{}).
//		Where("erp_category_id = ?", category.ID).
//		Total(&count)
//
//	serialNumber := fmt.Sprintf("%s%04d", category.Number, count+1)
//	fmt.Println("商品编号:", serialNumber)
//	return serialNumber, nil
//}

// GenerateSerialNumber 生成商品编号
func GenerateSerialNumber(categoryId uint32) (string, error) {
	// 查询商品分类
	var category ErpCategory
	if err := orm.Eloquent.Debug().Model(&ErpCategory{}).
		Where("id = ?", categoryId).First(&category).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return "", errors.New("未查到商品分类")
		}
		return "", err
	}

	// 查询该商品分类下最大的商品编号
	var maxSerialNumber sql.NullString
	if err := orm.Eloquent.Debug().Model(&ErpCommodity{}).
		Where("erp_category_id = ?", categoryId).
		Select("MAX(serial_number)").
		Row().Scan(&maxSerialNumber); err != nil && !errors.Is(err, sql.ErrNoRows) {
		return "", err
	}

	// 处理 NULL 值
	var lastNumber uint64
	if maxSerialNumber.Valid {
		lastSerial := maxSerialNumber.String
		lastNumberStr := lastSerial[len(category.Number):]
		lastNumber, _ = strconv.ParseUint(lastNumberStr, 10, 32)
	}

	// 递增生成新的商品编号
	newNumber := lastNumber + 1

	serialNumber := fmt.Sprintf("%s%04d", category.Number, newNumber)
	fmt.Println("商品编号:", serialNumber)
	return serialNumber, nil
}

// UpdateErpStockAmountInfo 更新库存和库存商品表的金额：指导零售价、最低零售价
func UpdateErpStockAmountInfo(begin *gorm.DB, req *CommodityEditRequest, barCode, serial_number string, category *ErpCategory) error {
	if category != nil && category.ID != 0 { // 分类信息有值
		// 更新库存表
		err := begin.Table("erp_stock").Where("erp_commodity_id=?", req.Id).
			Updates(map[string]interface{}{
				"retail_price":            req.RetailPrice,
				"min_retail_price":        req.MinRetailPrice,
				"erp_category_id":         category.ID,
				"erp_category_name":       category.Name,
				"erp_commodity_name":      req.Name,
				"commodity_serial_number": serial_number,
			}).Error
		if err != nil {
			return err
		}

		// 更新库存商品表
		err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5)", req.Id).
			Updates(map[string]interface{}{
				"retail_price":     req.RetailPrice,
				"min_retail_price": req.MinRetailPrice,
				//"staff_cost_price":  staffCostPrice,
				"erp_barcode":             barCode,
				"erp_category_id":         category.ID,
				"erp_category_name":       category.Name,
				"erp_commodity_name":      req.Name,
				"commodity_serial_number": serial_number,
			}).Error
		if err != nil {
			return err
		}

		// 更新采购商品表（除"已完成"、"已终止"都需要更新）
		var commodityIDs []uint32
		err = begin.Table("erp_purchase_commodity AS epc").
			Joins("JOIN erp_purchase_order AS epo ON epc.erp_purchase_order_id = epo.id").
			Where("epc.erp_commodity_id = ? AND epo.state NOT IN ?", req.Id,
				[]uint{ErpPurchaseOrderFinished, ErpPurchaseOrderEnd}).
			Pluck("epc.id", &commodityIDs).Error
		if err != nil {
			return err
		}

		if len(commodityIDs) > 0 {
			err = begin.Model(&ErpPurchaseCommodity{}).
				Where("id IN ?", commodityIDs).
				Updates(map[string]interface{}{
					"retail_price":            req.RetailPrice,
					"erp_commodity_name":      req.Name,
					"commodity_serial_number": serial_number,
				}).Error
			if err != nil {
				return err
			}
		}
	} else {
		// 更新库存表
		err := begin.Table("erp_stock").Where("erp_commodity_id=?", req.Id).
			Updates(map[string]interface{}{
				"retail_price":       req.RetailPrice,
				"min_retail_price":   req.MinRetailPrice,
				"erp_commodity_name": req.Name,
			}).Error
		if err != nil {
			return err
		}

		// 更新库存商品表
		err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5)", req.Id).
			Updates(map[string]interface{}{
				"retail_price":     req.RetailPrice,
				"min_retail_price": req.MinRetailPrice,
				//"staff_cost_price": staffCostPrice,
				"erp_barcode":        barCode,
				"erp_commodity_name": req.Name,
			}).Error
		if err != nil {
			return err
		}

		// 更新采购商品表（除"已完成"、"已终止"都需要更新）
		var commodityIDs []uint32
		err = begin.Table("erp_purchase_commodity AS epc").
			Joins("JOIN erp_purchase_order AS epo ON epc.erp_purchase_order_id = epo.id").
			Where("epc.erp_commodity_id = ? AND epo.state NOT IN ?", req.Id,
				[]uint{ErpPurchaseOrderFinished, ErpPurchaseOrderEnd}).
			Pluck("epc.id", &commodityIDs).Error
		if err != nil {
			return err
		}

		if len(commodityIDs) > 0 {
			err = begin.Model(&ErpPurchaseCommodity{}).
				Where("id IN ?", commodityIDs).
				Updates(map[string]interface{}{
					"retail_price":       req.RetailPrice,
					"erp_commodity_name": req.Name,
				}).Error
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// CheckCommodityIsHavaStock 检查某个商品是否还有库存
func CheckCommodityIsHavaStock(commodityId uint32) bool {
	var count int64
	err := orm.Eloquent.Table("erp_stock").Where("erp_commodity_id = ? and count > 0", commodityId).
		Count(&count).Error
	if err != nil {
		logger.Error("CheckCommodityIsHavaStock err:", logger.Field("err", err))
	}

	return count > 0
}

// IsExistingCommodity 检查是否存在某个商品
func IsExistingCommodity(commodityId uint32) bool {
	var count int64
	err := orm.Eloquent.Table("erp_commodity").Where("id = ?", commodityId).
		Count(&count).Error
	if err != nil {
		logger.Error("IsExistingCommodity err:", logger.Field("err", err))
	}

	return count > 0
}

// 校验导入零售excel格式
// 必填项：商品名称、销售数量
// 商品名称和串码是否对应
// 串码商品数量只能为1
// 是否有库存
//func checkOrderExcel(sheetCols [][]string) error {
//	if len(sheetCols) != 8 {
//		return errors.New("模版错误，请检查文件")
//	}
//
//	maxLength := findMaxLength(sheetCols)
//	nLow, nMax := determineLowAndMax(sheetCols)
//
//	if nMax < maxLength {
//		return errors.New("第" + strconv.Itoa(nMax+1) + "行商品名称和商品编号不能同时为空")
//	}
//
//	// 判断是否有重复串码
//	if duplicateName, nFlag := hasDuplicateIMEI(sheetCols[2]); nFlag {
//		return fmt.Errorf("商品串码不允许重复，请检查:[%v]", duplicateName)
//	}
//
//	//先遍历第1列
//	for i := 1; i < nLow; i++ {
//		if sheetCols[0][i] == "" && sheetCols[1][i] == "" { // 商品名称和编号不能都为空
//			return errors.New("第" + strconv.Itoa(i+1) + "行商品名称和商品编号不能同时为空")
//		}
//	}
//
//	for i := 1; i < nMax; i++ {
//		if i < len(sheetCols[1]) {
//			if !IsExistingProduct(sheetCols[1][i]) {
//				return errors.New("第" + strconv.Itoa(i+1) + "行商品不存在")
//			}
//		}
//
//		// 商品编号必须为纯数字
//		if i < len(sheetCols[0]) {
//			if sheetCols[0][i] != "" {
//				if _, err := strconv.Atoi(sheetCols[0][i]); err != nil {
//					return errors.New("第" + strconv.Itoa(i+1) + "行商品编号必须为纯数字")
//				}
//			}
//
//			if !isExistingProductCode(sheetCols[0][i]) {
//				return errors.New("第" + strconv.Itoa(i+1) + "行商品编号不存在")
//			}
//		}
//
//		// 所属门店不能为空
//		if i < len(sheetCols[4]) {
//			if sheetCols[4][i] == "" {
//				return errors.New("第" + strconv.Itoa(i+1) + "行所属门店不能为空")
//			}
//			if !isExistingStore(sheetCols[4][i]) {
//				return errors.New("第" + strconv.Itoa(i+1) + "行门店不存在")
//			}
//		}
//
//		// 数量必须为正整数
//		if i < len(sheetCols[3]) {
//			if quantity, err := strconv.Atoi(sheetCols[3][i]); err != nil || quantity < 1 {
//				return errors.New("第" + strconv.Itoa(i+1) + "行数量必须是大于等于1的整数")
//			}
//		}
//
//		// 串码商品数量只能为1
//		var nCount int
//		if i < len(sheetCols[3]) {
//			if i < len(sheetCols[3]) {
//				nCount, _ = strconv.Atoi(sheetCols[3][i])
//			}
//
//			// 串码类商品数量只能为1
//			if sheetCols[2][i] != "" && nCount != 1 {
//				return errors.New("第" + strconv.Itoa(i+1) + "行串码类商品数量只能为1")
//			}
//		}
//
//		// 判断商品是否赠送
//		if i < len(sheetCols[6]) {
//			if sheetCols[6][i] != "是" && sheetCols[6][i] != "" {
//				return errors.New("第" + strconv.Itoa(i+1) + "行商品是否赠送填写有误")
//			}
//		}
//
//		// 查询商品是否有库存
//		if sheetCols[2][i] != "" { // 串码商品
//			var imeiStockCommodity ErpStockCommodity
//			err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?",
//				sheetCols[2][i], InStock).
//				Find(&imeiStockCommodity).Error
//			if err != nil {
//				return err
//			}
//			if imeiStockCommodity.ID == 0 {
//				return errors.New("第" + strconv.Itoa(i+1) + "行商品不存在")
//			}
//			// 门店对比
//			if imeiStockCommodity.StoreName != sheetCols[4][i] {
//				return errors.New("第" + strconv.Itoa(i+1) + "行商品" +
//					"[" + imeiStockCommodity.ErpCommodityName + "]非所选门店库存，请检查")
//			}
//			// 零售价对比
//			var floatVal float64
//			if i < len(sheetCols[5]) {
//				if sheetCols[5][i] != "" {
//					floatVal, err = strconv.ParseFloat(sheetCols[5][i], 64)
//					if err != nil {
//						return errors.New("第" + strconv.Itoa(i+1) + "行零售价有误")
//					}
//					strMin := strconv.FormatFloat(imeiStockCommodity.MinRetailPrice, 'f', 2, 64)
//					if floatVal < imeiStockCommodity.MinRetailPrice {
//						return errors.New("第" + strconv.Itoa(i+1) + "行零售价有误，不能低于最低零售价[" + strMin + "]")
//					}
//				}
//			}
//		} else { // 非串码商品
//			var count int64
//			var err error
//			if sheetCols[0][i] != "" { // 商品编号不为空
//				err = orm.Eloquent.Table("erp_stock_commodity").
//					Where("commodity_serial_number = ? and store_name = ? and state = ? and imei_type = ?",
//						sheetCols[0][i], sheetCols[4][i], InStock, NoIMEICommodity).
//					Count(&count).Error
//			} else {
//				err = orm.Eloquent.Table("erp_stock_commodity").
//					Where("erp_commodity_name = ? and store_name = ? and state = ? and imei_type = ?",
//						sheetCols[1][i], sheetCols[4][i], InStock, NoIMEICommodity).
//					Count(&count).Error
//			}
//			if err != nil {
//				return errors.New("第" + strconv.Itoa(i+1) + "行商品不存在")
//			}
//
//			if count < int64(nCount) {
//				// 获取商品名称
//				return errors.New("第" + strconv.Itoa(i+1) + "行商品" + "[" + sheetCols[1][i] + "]库存不足")
//			}
//		}
//	}
//
//	return nil
//}

func checkOrderExcel(c *gin.Context, sheetCols [][]string, storeId int) error {
	// 校验列数是否正确
	if len(sheetCols) != 8 {
		return errors.New("模版错误，请检查文件")
	}

	// 获取最大行数
	nMax := findMaxLength(sheetCols)
	if nMax == 0 {
		return errors.New("模版内容为空")
	}

	// 校验商品串码是否重复
	if duplicateName, nFlag := hasDuplicateIMEI(sheetCols[2]); nFlag {
		return fmt.Errorf("商品串码不允许重复，请检查:[%v]", duplicateName)
	}

	// 判断门店名称是否有不同
	if duplicateName, nFlag := hasDuplicateStore(sheetCols); nFlag {
		return fmt.Errorf("门店名称不同，请检查:[%v]", duplicateName)
	}

	orderStore, err := GetStore(uint32(storeId))
	if err != nil {
		return err
	}

	if sheetCols[4][1] != orderStore.Name {
		return fmt.Errorf("导入数据门店[%s]与订单门店[%s]不同，请检查", sheetCols[4][1], orderStore.Name)
	}

	// 缓存商品编号、商品名称和门店查询结果
	productCodeCache := make(map[string]bool)
	productNameCache := make(map[string]bool)
	storeCache := make(map[string]bool)

	// 预加载所有商品编号、商品名称和门店
	loadAllProductsIntoCache(productCodeCache, productNameCache)
	loadAllStoresIntoCache(storeCache)

	// 通道用于并发校验
	var wg sync.WaitGroup
	errCh := make(chan error, nMax)

	// 限制最大并发数量
	maxConcurrency := 10
	sem := make(chan struct{}, maxConcurrency)

	for i := 1; i < nMax; i++ {
		// 校验行是否越界
		if !isRowValid(sheetCols, i) {
			continue
		}

		// 等待一个空位
		sem <- struct{}{}
		wg.Add(1)
		go func(row int) {
			defer wg.Done()
			defer func() { <-sem }() // 完成任务后释放空位

			if err := validateRow(sheetCols, row, productCodeCache, productNameCache, storeCache); err != nil {
				errCh <- fmt.Errorf("第 %d 行: %v", row+1, err)
			}
		}(i)
	}

	wg.Wait()
	close(errCh)

	// 返回第一个错误
	for err := range errCh {
		return err
	}

	validateStock(c, sheetCols)

	return nil
}

// 检查第 row 行是否所有列都有有效数据
func isRowValid(sheetCols [][]string, row int) bool {
	for _, col := range sheetCols {
		if row >= len(col) { // 行数超出当前列的长度
			return false
		}
	}
	return true
}

// 批量加载商品信息到缓存
func loadAllProductsIntoCache(productCodeCache, productNameCache map[string]bool) {
	var products []ErpCommodity
	orm.Eloquent.Debug().Find(&products)
	for _, product := range products {
		productCodeCache[product.SerialNumber] = true
		productNameCache[product.Name] = true
	}
}

// 批量加载门店信息到缓存
func loadAllStoresIntoCache(storeCache map[string]bool) {
	var stores []Store
	orm.Eloquent.Debug().Find(&stores)
	for _, store := range stores {
		storeCache[store.Name] = true
	}
}

// 校验单行数据
func validateRow(sheetCols [][]string, row int, productCodeCache, productNameCache, storeCache map[string]bool) error {
	fmt.Println("row is:", row)
	// 校验商品名称和商品编号
	if sheetCols[0][row] == "" && sheetCols[1][row] == "" {
		//return errors.New("商品名称和商品编号不能同时为空")
	}

	// 校验商品编号是否存在
	if sheetCols[0][row] != "" {
		if _, err := strconv.Atoi(sheetCols[0][row]); err != nil {
			return errors.New("商品编号必须为纯数字")
		}
		if !productCodeCache[sheetCols[0][row]] {
			return errors.New("商品编号不存在")
		}
	}

	// 校验商品名称是否存在
	if sheetCols[1][row] != "" && !productNameCache[sheetCols[1][row]] {
		return errors.New("商品名称不存在")
	}

	// 校验所属门店是否存在
	if sheetCols[4][row] == "" || !storeCache[sheetCols[4][row]] {
		return errors.New("所属门店不能为空或不存在")
	}

	// 校验数量是否为正整数
	if quantity, err := strconv.Atoi(sheetCols[3][row]); err != nil || quantity < 1 {
		return errors.New("数量必须是大于等于1的整数")
	}

	// 校验串码商品数量只能为1
	if sheetCols[2][row] != "" && sheetCols[3][row] != "1" {
		return errors.New("串码类商品数量只能为1")
	}

	// 校验商品是否赠送
	if sheetCols[6][row] != "" && sheetCols[6][row] != "是" {
		return errors.New("商品是否赠送填写有误")
	}

	return nil
}

// validateStock 校验库存信息
func validateStock(c *gin.Context, sheetCols [][]string) error {
	// 预加载所有库存数据，按门店 store_id 过滤
	var imeiStockCommodities []ErpStockCommodity
	err := orm.Eloquent.Table("erp_stock_commodity").
		Where("state = ? AND store_name = ?", InStock, sheetCols[4][1]).
		Find(&imeiStockCommodities).Error
	if err != nil {
		return fmt.Errorf("加载库存数据失败: %v", err)
	}

	// 构建库存缓存：按 imei 和非串码商品分组
	imeiStockMap := make(map[string]ErpStockCommodity)   // 串码商品缓存
	nonIMEIStockMap := make(map[string]map[string]int64) // 非串码商品库存，按 store -> commodity 分组
	for _, stock := range imeiStockCommodities {
		if stock.IMEI != "" {
			imeiStockMap[stock.IMEI] = stock
		} else {
			if _, exists := nonIMEIStockMap[stock.StoreName]; !exists {
				nonIMEIStockMap[stock.StoreName] = make(map[string]int64)
			}
			key := stock.CommoditySerialNumber
			if key == "" {
				key = stock.ErpCommodityName
			}
			nonIMEIStockMap[stock.StoreName][key]++
		}
	}

	// 校验库存信息
	for row := 1; row < len(sheetCols[0]); row++ {
		if sheetCols[2][row] != "" { // 串码商品
			stock, exists := imeiStockMap[sheetCols[2][row]]
			if !exists {
				return fmt.Errorf("第 %d 行: 串码商品不存在或无库存", row+1)
			}
			if stock.StoreName != sheetCols[4][row] {
				return fmt.Errorf("第 %d 行: 商品[%s]非所选门店库存，请检查", row+1, stock.ErpCommodityName)
			}
			if sheetCols[5][row] != "" {
				price, err := strconv.ParseFloat(sheetCols[5][row], 64)
				if err != nil || price < stock.MinRetailPrice {
					if !HasPermission(c) {
						logger.Error("SalePrice less than MinRetailPrice")
						return fmt.Errorf("第 %d 行: 零售价有误，不能低于最低零售价[%.2f]", row+1, stock.MinRetailPrice)
					}

				}
			}
		} else { // 非串码商品
			storeName := sheetCols[4][row]
			commodityKey := sheetCols[0][row]
			if commodityKey == "" {
				commodityKey = sheetCols[1][row]
			}
			storeStock, storeExists := nonIMEIStockMap[storeName]
			if !storeExists || storeStock[commodityKey] < 1 {
				return fmt.Errorf("第 %d 行: 商品[%s]库存不足", row+1, sheetCols[1][row])
			}
		}
	}

	return nil
}

//// 校验库存信息
//func validateStock(sheetCols [][]string, row int) error {
//	if sheetCols[2][row] != "" { // 串码商品
//		var imeiStockCommodity ErpStockCommodity
//		err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? AND state = ?",
//			sheetCols[2][row], InStock).Find(&imeiStockCommodity).Error
//		if err != nil || imeiStockCommodity.ID == 0 {
//			return errors.New("串码商品不存在或无库存")
//		}
//		if imeiStockCommodity.StoreName != sheetCols[4][row] {
//			return fmt.Errorf("商品[%s]非所选门店库存，请检查", imeiStockCommodity.ErpCommodityName)
//		}
//		if sheetCols[5][row] != "" {
//			if price, err := strconv.ParseFloat(sheetCols[5][row], 64); err != nil || price < imeiStockCommodity.MinRetailPrice {
//				return fmt.Errorf("零售价有误，不能低于最低零售价[%.2f]", imeiStockCommodity.MinRetailPrice)
//			}
//		}
//	} else { // 非串码商品
//		var count int64
//		err := orm.Eloquent.Table("erp_stock_commodity").
//			Where("(commodity_serial_number = ? OR erp_commodity_name = ?) AND store_name = ? AND state = ? AND imei_type = ?",
//				sheetCols[0][row], sheetCols[1][row], sheetCols[4][row], InStock, NoIMEICommodity).
//			Count(&count).Error
//		if err != nil || count < 1 {
//			return fmt.Errorf("商品[%s]库存不足", sheetCols[1][row])
//		}
//	}
//
//	return nil
//}

// 将读取的excel数据转换成OrderExcel struct
func transOrderData(colsMap []map[string]interface{}) ([]OrderExcel, error) {
	var stockInfos []OrderExcel

	// 遍历 colsMap 进行类型断言和转换
	for _, col := range colsMap {
		var stockInfo OrderExcel

		// 将 col 转换为 JSON 字符串
		jsonData, err := json.Marshal(col)
		if err != nil {
			return nil, fmt.Errorf("failed to marshal data to JSON: %v", err)
		}

		// 将 JSON 字符串反序列化为 CommodityExcel
		if err := json.Unmarshal(jsonData, &stockInfo); err != nil {
			return nil, fmt.Errorf("failed to unmarshal JSON to StockExcel: %v", err)
		}

		// 将处理后的数据追加到 commodities 中
		stockInfos = append(stockInfos, stockInfo)
	}

	return stockInfos, nil
}

func ImportOrderData(c *gin.Context, colsMap []map[string]interface{}) ([]ErpOrderCommodity, error) {
	list, err := transOrderData(colsMap)
	if err != nil {
		return nil, err
	}

	var orderCommodities []ErpOrderCommodity
	for i, _ := range list {
		var orderCommodity ErpOrderCommodity

		// 商品数量
		var nCount int
		nCount, _ = strconv.Atoi(list[i].Count)

		// 判断商品是否赠送
		var nPresentType uint32
		nPresentType = 1
		if i < len(list[i].PresentType) {
			if list[i].PresentType == "是" {
				nPresentType = 2
			}
		}

		// 查询商品是否有库存
		if list[i].IMEI != "" { // 串码商品
			var imeiStockCommodity ErpStockCommodity
			err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?",
				list[i].IMEI, InStock).
				Find(&imeiStockCommodity).Error
			if err != nil {
				return nil, err
			}
			if imeiStockCommodity.ID == 0 {
				return nil, errors.New("第" + strconv.Itoa(i+1) + "行商品不存在")
			}
			// 门店对比
			if imeiStockCommodity.StoreName != list[i].StoreName {
				return nil, errors.New("第" + strconv.Itoa(i+1) + "行商品" +
					"[" + imeiStockCommodity.ErpCommodityName + "]非所选门店库存，请检查")
			}
			// 零售价对比
			var floatVal float64
			if list[i].SalePrice != "" {
				floatVal, err = strconv.ParseFloat(list[i].SalePrice, 64)
				if err != nil {
					return nil, errors.New("第" + strconv.Itoa(i+1) + "行零售价有误")
				}
				strMin := strconv.FormatFloat(imeiStockCommodity.MinRetailPrice, 'f', 2, 64)
				if floatVal < imeiStockCommodity.MinRetailPrice {
					if !HasPermission(c) {
						return nil, errors.New("第" + strconv.Itoa(i+1) + "行零售价有误，不能低于最低零售价[" + strMin + "]")
					}
				}
			} else {
				floatVal = imeiStockCommodity.RetailPrice
			}

			orderCommodity.ErpCategoryId = imeiStockCommodity.ErpCategoryId
			orderCommodity.ErpCategoryName = imeiStockCommodity.ErpCategoryName
			orderCommodity.ErpCommodityId = imeiStockCommodity.ErpCommodityId
			orderCommodity.ErpCommodityName = imeiStockCommodity.ErpCommodityName
			orderCommodity.ErpSupplierId = imeiStockCommodity.ErpSupplierId
			orderCommodity.ErpSupplierName = imeiStockCommodity.ErpSupplierName
			orderCommodity.IMEIType = imeiStockCommodity.IMEIType
			orderCommodity.IMEI = imeiStockCommodity.IMEI
			orderCommodity.PresentType = nPresentType
			orderCommodity.RetailPrice = imeiStockCommodity.RetailPrice
			orderCommodity.SalePrice = floatVal
			orderCommodity.ReceivedAmount = floatVal
			orderCommodity.SaleDiscount = imeiStockCommodity.RetailPrice - floatVal
			orderCommodity.WholesalePrice = imeiStockCommodity.WholesalePrice
			orderCommodity.StaffCostPrice = imeiStockCommodity.StaffCostPrice
			orderCommodity.MemberDiscount = imeiStockCommodity.MemberDiscount
			orderCommodity.SalesProfit = floatVal - imeiStockCommodity.WholesalePrice
			orderCommodity.StaffProfit = floatVal - imeiStockCommodity.StaffCostPrice
			orderCommodity.Count = int32(nCount)
			orderCommodity.Remark = list[i].Remark

		} else { // 非串码商品
			var count int64
			var imeiStockCommodities []ErpStockCommodity
			if list[i].SerialNum != "" { // 商品编号不为空
				err = orm.Eloquent.Table("erp_stock_commodity").
					Where("commodity_serial_number = ? and store_name = ? and state = ? and imei_type = ?",
						list[i].SerialNum, list[i].StoreName, InStock, NoIMEICommodity).
					Count(&count).Error
			} else {
				err = orm.Eloquent.Table("erp_stock_commodity").
					Where("erp_commodity_name = ? and store_name = ? and state = ? and imei_type = ?",
						list[i].Name, list[i].StoreName, InStock, NoIMEICommodity).
					Count(&count).Error
			}
			if err != nil {
				return nil, errors.New("第" + strconv.Itoa(i+1) + "行商品不存在")
			}

			if count < int64(nCount) {
				// 获取商品名称
				return nil, errors.New("第" + strconv.Itoa(i+1) + "行商品" + "[" + list[i].Name + "]库存不足")
			}

			if list[i].SerialNum != "" { // 商品编号不为空
				err = orm.Eloquent.Table("erp_stock_commodity").
					Where("commodity_serial_number = ? and store_name = ? and state = ? and imei_type = ?",
						list[i].SerialNum, list[i].StoreName, InStock, NoIMEICommodity).
					Find(&imeiStockCommodities).Order("first_stock_time DESC").Error
			} else {
				err = orm.Eloquent.Table("erp_stock_commodity").
					Where("erp_commodity_name = ? and store_name = ? and state = ? and imei_type = ?",
						list[i].Name, list[i].StoreName, InStock, NoIMEICommodity).
					Find(&imeiStockCommodities).Order("first_stock_time DESC").Error
			}
			if err != nil {
				return nil, errors.New("第" + strconv.Itoa(i+1) + "行商品不存在")
			}

			if len(imeiStockCommodities) == 0 {
				return nil, errors.New("第" + strconv.Itoa(i+1) + "行商品不存在")
			}

			// 零售价对比
			var floatVal float64
			if list[i].SalePrice != "" {
				floatVal, err = strconv.ParseFloat(list[i].SalePrice, 64)
				if err != nil {
					return nil, errors.New("第" + strconv.Itoa(i+1) + "行零售价有误")
				}
				strMin := strconv.FormatFloat(imeiStockCommodities[0].MinRetailPrice, 'f', 2, 64)
				if floatVal < imeiStockCommodities[0].MinRetailPrice {
					if !HasPermission(c) {
						return nil, errors.New("第" + strconv.Itoa(i+1) + "行零售价有误，不能低于最低零售价[" + strMin + "]")
					}
				}
			} else {
				floatVal = imeiStockCommodities[0].RetailPrice
			}

			orderCommodity.ErpCategoryId = imeiStockCommodities[0].ErpCategoryId
			orderCommodity.ErpCategoryName = imeiStockCommodities[0].ErpCategoryName
			orderCommodity.ErpCommodityId = imeiStockCommodities[0].ErpCommodityId
			orderCommodity.ErpCommodityName = imeiStockCommodities[0].ErpCommodityName
			orderCommodity.ErpSupplierId = imeiStockCommodities[0].ErpSupplierId
			orderCommodity.ErpSupplierName = imeiStockCommodities[0].ErpSupplierName
			orderCommodity.IMEIType = imeiStockCommodities[0].IMEIType
			orderCommodity.IMEI = imeiStockCommodities[0].IMEI
			orderCommodity.PresentType = nPresentType
			orderCommodity.RetailPrice = imeiStockCommodities[0].RetailPrice
			orderCommodity.SalePrice = floatVal
			orderCommodity.ReceivedAmount = floatVal
			orderCommodity.SaleDiscount = imeiStockCommodities[0].RetailPrice - floatVal
			orderCommodity.WholesalePrice = imeiStockCommodities[0].WholesalePrice
			orderCommodity.StaffCostPrice = imeiStockCommodities[0].StaffCostPrice
			orderCommodity.MemberDiscount = imeiStockCommodities[0].MemberDiscount
			orderCommodity.SalesProfit = floatVal - imeiStockCommodities[0].WholesalePrice
			orderCommodity.StaffProfit = floatVal - imeiStockCommodities[0].StaffCostPrice
			orderCommodity.Count = int32(nCount)
			orderCommodity.Remark = list[i].Remark
		}

		orderCommodities = append(orderCommodities, orderCommodity)
	}

	return orderCommodities, nil
}
