// 思迅数据同步
package services

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/goccy/go-json" // 使用性能更好的JSON库
	"github.com/spf13/viper"

	"fafa-crawler/src/beans"
	"fafa-crawler/src/mapper"
	"fafa-crawler/src/models"
	"fafa-crawler/src/util"

	"gorm.io/gorm"
)

const (
	BatchSize = 400
)

var ()

type SxGoodsService struct {
	db *gorm.DB // Add database connection
}

func NewSxGoodsService() *SxGoodsService {
	return sxGoodsService
}

// ProcessSiXunGoodsData 高效处理思迅商品数据的综合方法
// 执行顺序: 1. JSON数据转换 2. 图片文件过滤 3. 批量保存到数据库 4. 上传图片到COS
func (s *SxGoodsService) ProcessSiXunGoodsData(path string) (srcDataCnt, filteredDataCnt, savedDataCnt, filteredImgCnt int64) {
	// 步骤1: JSON数据转换
	srcDataCnt, targetDataCnt, sxBeanList := s.JsonDataConvBeans(path)
	if targetDataCnt == 0 || len(sxBeanList) == 0 {
		log.Printf("JSON数据转换失败或无有效数据")
		return srcDataCnt, 0, 0, 0
	}
	log.Printf("JSON数据转换完成: 源数据%d条，转换成功%d条", srcDataCnt, targetDataCnt)

	// 步骤2: 图片文件过滤
	filteredRecords, filteredDataCnt, filteredImgCnt := s.filterSiXunGoodsBeans(path, sxBeanList)
	if filteredDataCnt == 0 {
		log.Printf("图片文件过滤后无有效数据")
		return srcDataCnt, filteredDataCnt, 0, filteredImgCnt
	}
	log.Printf("图片文件过滤完成: 有效记录%d条，有效图片%d张", filteredDataCnt, filteredImgCnt)

	// 步骤3: 批量保存到数据库
	savedDataCnt = s.BatchSaveSiXunProducts(filteredRecords)
	log.Printf("批量保存完成: 成功保存%d条记录", savedDataCnt)

	// 步骤4: 上传图片到COS
	if err := s.uploadImagesToCOS(path); err != nil {
		log.Printf("上传图片到COS失败: %v", err)
	}

	return srcDataCnt, filteredDataCnt, savedDataCnt, filteredImgCnt
}

// uploadImagesToCOS 上传图片到COS
func (s *SxGoodsService) uploadImagesToCOS(path string) error {
	// 获取当前日期文件夹名称
	currentTime := time.Now()
	dateFolderName := currentTime.Format("20060102")
	localImageDir := filepath.Join(path, dateFolderName)

	// 从配置文件读取COS配置
	if err := s.loadCOSConfig(); err != nil {
		return fmt.Errorf("加载COS配置失败: %w", err)
	}

	// 获取COS工具类实例
	cosConfig := util.COSConfig{
		BucketURL: viper.GetString("cossdk.bucket_url"),
		SecretID:  viper.GetString("cossdk.secret_id"),
		SecretKey: viper.GetString("cossdk.secret_key"),
		BasePath:  viper.GetString("cossdk.base_path"),
	}

	cosUtil, err := util.GetCOSUtil(cosConfig)
	if err != nil {
		return fmt.Errorf("获取COS工具类实例失败: %w", err)
	}

	// 并发上传图片到COS
	if err := cosUtil.ConcurrentUploadDirectory(localImageDir, dateFolderName, 10); err != nil {
		return fmt.Errorf("上传图片到COS失败: %w", err)
	}

	log.Printf("图片上传到COS完成: 上传目录 %s", localImageDir)
	return nil
}

// loadCOSConfig 从配置文件加载COS配置
func (s *SxGoodsService) loadCOSConfig() error {
	viper.SetConfigFile("./config/config.toml")
	viper.SetConfigType("toml")

	if err := viper.ReadInConfig(); err != nil {
		return fmt.Errorf("读取配置文件失败: %w", err)
	}

	return nil
}

// JsonDataConvBeans 将JSON数据转换为SiXunGoodsBean对象数组
func (s *SxGoodsService) JsonDataConvBeans(path string) (srcDataCnt, targetDataCnt int64, sxBeanList []*beans.SiXunGoodsBean) {
	// 构建完整的文件路径
	jsonFilePath := filepath.Join(path, "data", "product_data.json")

	// 读取JSON文件
	data, err := os.ReadFile(jsonFilePath)
	if err != nil {
		log.Printf("读取JSON文件失败: %v", err)
		return 0, 0, nil
	}

	// 定义临时结构体来解析JSON数据
	type tempImage struct {
		ProductID string `json:"product_id"`
		Barcode   string `json:"barcode"`
		ImageURL  string `json:"image_url"`
		Seq       int32  `json:"seq"`
		IsMain    int32  `json:"is_main"`
	}

	type tempProduct struct {
		ProductID   string      `json:"product_id"`
		Name        string      `json:"name"`
		Title       string      `json:"title"`
		Barcode     string      `json:"barcode"`
		Category1st string      `json:"category_1st"`
		Category2nd string      `json:"category_2nd"`
		Price       float64     `json:"price"`
		Keywords    string      `json:"keywords"`
		Thumb       string      `json:"thumb"`
		Brand       string      `json:"brand"`
		Spec        string      `json:"spec"`
		Weight      float64     `json:"weight"`
		WeightUnit  string      `json:"weight_unit"`
		Intro       string      `json:"intro"`
		ImagesList  []tempImage `json:"images_list"`
	}

	// 解析JSON数据（使用高性能JSON库）
	var tempProducts []tempProduct
	if err := json.Unmarshal(data, &tempProducts); err != nil {
		log.Printf("解析JSON数据失败: %v", err)
		return 0, 0, nil
	}

	// 设置源数据计数
	srcDataCnt = int64(len(tempProducts))

	// 转换为SiXunGoodsBean对象数组
	var siXunGoodsBeans []*beans.SiXunGoodsBean
	for _, tempProd := range tempProducts {
		// 创建LibraryProduct模型
		product := &models.LibraryProduct{
			Name:        tempProd.Name,
			Sname:       tempProd.Name,
			Title:       tempProd.Title,
			Barcode:     tempProd.Barcode,
			Category1St: tempProd.Category1st,
			Category2Nd: tempProd.Category2nd,
			Price:       tempProd.Price,
			Keywords:    tempProd.Keywords,
			Thumb:       tempProd.Thumb,
			Brand:       tempProd.Brand,
			Spec:        tempProd.Spec,
			Weight:      fmt.Sprintf("%.2f", tempProd.Weight),
			WeightUnit:  tempProd.WeightUnit,
			Intro:       tempProd.Intro,
			Source:      fmt.Sprintf("sixun_%s", tempProd.ProductID),
		}

		// 如果Category2Nd为空，使用Category1st的值
		if product.Category2Nd == "" {
			product.Category2Nd = product.Category1St
		}
		product.Category = product.Category2Nd

		// 如果Intro为空，使用Title的值
		if product.Intro == "" {
			product.Intro = product.Title
		}

		// 创建LibraryProductImage模型列表
		var productImages []*models.LibraryProductImage
		for _, tempImg := range tempProd.ImagesList {
			image := &models.LibraryProductImage{
				ImageURL: tempImg.ImageURL,
				Seq:      tempImg.Seq,
				IsMain:   tempImg.IsMain,
			}
			productImages = append(productImages, image)
		}

		// 创建SiXunGoodsBean
		bean := &beans.SiXunGoodsBean{
			Product:   product,
			ImageList: productImages,
		}

		siXunGoodsBeans = append(siXunGoodsBeans, bean)
	}

	// 设置转换成功记录数
	targetDataCnt = int64(len(siXunGoodsBeans))

	return srcDataCnt, targetDataCnt, siXunGoodsBeans
}

// filterSiXunGoodsBeans 过滤思迅商品记录，检查图片文件是否存在
func (s *SxGoodsService) filterSiXunGoodsBeans(path string, records []*beans.SiXunGoodsBean) (filteredRecords []*beans.SiXunGoodsBean, targetDataCnt, targetImgCnt int64) {
	// 创建日期格式的文件夹
	currentTime := time.Now()
	dateFolderName := currentTime.Format("20060102")
	dateFolderPath := filepath.Join(path, dateFolderName)

	// 确保日期文件夹存在
	if err := os.MkdirAll(dateFolderPath, 0755); err != nil {
		log.Printf("创建日期文件夹失败: %v", err)
		return records, int64(len(records)), 0
	}

	// 遍历所有记录
	for _, record := range records {
		// 创建新的图片列表，只包含存在的图片
		var validImages []*models.LibraryProductImage
		validImageCount := int64(0)

		// 检查每个图片是否存在
		for _, image := range record.ImageList {
			imagePath := filepath.Join(path, "images", image.ImageURL)

			// 检查文件是否存在
			if _, err := os.Stat(imagePath); err == nil {
				// 文件存在，添加到有效图片列表
				validImages = append(validImages, image)
				validImageCount++

				// 拷贝图片到日期文件夹（使用高性能文件拷贝工具）
				targetImagePath := filepath.Join(dateFolderPath, image.ImageURL)
				if err := util.CopyFile(imagePath, targetImagePath); err != nil {
					log.Printf("拷贝图片文件失败: %v", err)
				}

				// 更新图片路径为统一的实体示例路径
				image.ImageURL = fmt.Sprintf("/media/images/goods_library/%s/%s", dateFolderName, image.ImageURL)
			}
		}

		// 更新缩略图路径
		record.Product.Thumb = fmt.Sprintf("/media/images/goods_library/%s/%s", dateFolderName, record.Product.Thumb)

		// 如果有有效图片，则保留该记录
		if len(validImages) > 0 {
			// 更新记录的图片列表
			record.ImageList = validImages
			filteredRecords = append(filteredRecords, record)
			targetImgCnt += validImageCount
		}
	}

	targetDataCnt = int64(len(filteredRecords))
	return filteredRecords, targetDataCnt, targetImgCnt
}

// BatchSaveSiXunProducts 高效批量添加思迅商品和商品图片记录
func (s *SxGoodsService) BatchSaveSiXunProducts(records []*beans.SiXunGoodsBean) int64 {
	if len(records) == 0 {
		return 0
	}

	var successCount int64
	totalRecords := len(records)

	// 分批处理记录
	for i := 0; i < totalRecords; i += BatchSize {
		// 计算当前批次的结束索引
		end := i + BatchSize
		if end > totalRecords {
			end = totalRecords
		}

		// 获取当前批次的数据
		batch := records[i:end]

		// 处理当前批次
		count := s.saveSiXunProductBatch(batch)
		successCount += count

		log.Printf("思迅商品批量保存进度: %d/%d (当前批次保存成功: %d)\n", end, totalRecords, count)
	}

	return successCount
}

// saveSiXunProductBatch 保存思迅商品批次数据
func (s *SxGoodsService) saveSiXunProductBatch(batch []*beans.SiXunGoodsBean) int64 {
	var successCount int64

	// 使用事务确保数据一致性
	err := s.db.Transaction(func(tx *gorm.DB) error {
		// 创建临时存储商品和图片的切片
		var products []*models.LibraryProduct
		var allProductImages []*models.LibraryProductImage

		// 遍历批次中的每个商品
		for _, bean := range batch {
			// 检查商品是否已存在
			if s.IsExitsSiXun(bean.Product) {
				continue // 如果商品已存在，跳过
			}

			// 添加商品到待插入列表
			products = append(products, bean.Product)

			// 处理商品图片
			for _, image := range bean.ImageList {
				// 设置商品ID（在创建商品后会更新）
				image.ProductID = bean.Product.ID
				allProductImages = append(allProductImages, image)
			}
		}

		// 如果没有需要保存的商品，直接返回
		if len(products) == 0 {
			return nil
		}

		// 批量插入商品（使用批次大小）
		if err := tx.CreateInBatches(products, BatchSize).Error; err != nil {
			return fmt.Errorf("批量保存商品失败: %w", err)
		}

		// 更新图片中的商品ID并批量插入图片
		if len(allProductImages) > 0 {
			// 根据商品的条形码或名称匹配更新图片的商品ID
			for i, product := range products {
				for _, image := range allProductImages {
					// 这里假设图片已经正确关联到商品
					// 在实际应用中，可能需要更复杂的匹配逻辑
					if image.ProductID == 0 {
						image.ProductID = product.ID
					}
				}
				// 更新原始数据中的商品ID（如果需要）
				if i < len(batch) {
					batch[i].Product.ID = product.ID
				}
			}

			// 批量插入图片（使用批次大小）
			if err := tx.CreateInBatches(allProductImages, BatchSize).Error; err != nil {
				return fmt.Errorf("批量保存商品图片失败: %w", err)
			}
		}

		successCount = int64(len(products))
		return nil
	})

	if err != nil {
		log.Printf("思迅商品批量保存失败: %v", err)
		return 0
	}

	return successCount
}

// IsExitsSiXun 检查思迅商品是否已存在
func (s *SxGoodsService) IsExitsSiXun(record *models.LibraryProduct) bool {
	// 空记录直接返回不存在
	if record == nil {
		return false
	}

	m := mapper.LibraryProduct
	q := m.Select(m.ID)

	// 优先使用条形码查询，无条形码时使用商品名称查询
	if record.Barcode != "" {
		q = q.Where(m.Barcode.Eq(record.Barcode))
	} else if record.Name != "" {
		q = q.Where(m.Name.Eq(record.Name))
	} else {
		// 无有效查询条件
		return false
	}

	// 执行数量统计查询
	cnt, err := q.Count()
	if err != nil {
		log.Printf("查询思迅商品数量失败，错误: %v", err)
		return false
	}

	return cnt > 0
}

// IsExitsSiXunByBarcode 根据条形码检查思迅商品是否已存在
func (s *SxGoodsService) IsExitsSiXunByBarcode(barcode string) bool {
	if barcode == "" {
		return false
	}

	m := mapper.LibraryProduct
	q := m.Select(m.ID).Where(m.Barcode.Eq(barcode))

	// 执行数量统计查询
	cnt, err := q.Count()
	if err != nil {
		log.Printf("根据条形码查询思迅商品数量失败，错误: %v", err)
		return false
	}

	return cnt > 0
}
