package services

import (
	"context"
	"fmt"
	"log"

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

	"gorm.io/gorm"
)

var (
	filePath = "/media/images/goods_library/"
)

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

func NewProductService() *ProductService {
	return productService
}

// saveImageAndProductImage saves the image, creates the ProductImage record, and updates the product thumbnail.
func (s *ProductService) saveImageAndProductImage(ctx context.Context, tx *gorm.DB, productID uint64, pi *models.LibraryProductImage, p *models.LibraryProduct) error {
	fileName, err := util.SaveImageFromURL(pi.ImageURL, fmt.Sprintf("/%s/%d/", filePath, productID))
	if err != nil {
		log.Printf("保存图片失败: %v, URL: %s", err, pi.ImageURL)
		return err
	}

	pi.ImageURL = fileName // Update ImageURL to the local path
	pi.ProductID = productID

	if err := mapper.LibraryProductImage.WithContext(ctx).Create(pi); err != nil {
		log.Printf("创建 ProductImage 失败: %v, URL: %s", err, pi.ImageURL)
		return err
	}

	if pi.IsMain == 1 {
		// Update the main image in the product record
		p.Thumb = pi.ImageURL // Assuming Thumb is the main image field
		if _, err := mapper.LibraryProduct.WithContext(ctx).Where(mapper.LibraryProduct.ID.Eq(productID)).Update(mapper.LibraryProduct.Thumb, pi.ImageURL); err != nil {
			log.Printf("更新商品缩略图失败: %v, ProductID: %d", err, productID)
			return err
		}
	}
	return nil
}

// SaveProduct saves a single product.
func (s *ProductService) SaveProduct(record *beans.ProductBean) bool {
	if record == nil {
		log.Println("商品记录为空")
		return false
	}

	p, pis, err := record.ConvProductModel()
	if err != nil {
		log.Printf("转换商品模型失败: %v", err)
		return false
	}

	if s.IsExits(p) {
		log.Printf("商品已存在: %s", p.Name)
		return false
	}

	ctx := context.Background() // Create a context
	tx := s.db.Begin()          // Start a transaction
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
			log.Printf("事务 panic，已回滚: %v", r)
			panic(r)
		}
		if err := tx.Commit().Error; err != nil {
			tx.Rollback()
			log.Printf("提交事务失败: %v", err)
		}
	}()

	if err := mapper.LibraryProduct.WithContext(ctx).Create(p); err != nil {
		log.Printf("保存商品失败: %v", err)
		tx.Rollback()
		return false
	}

	for _, pi := range pis {
		if s.IsExitsProductImage(p.ID, pi.ImageURL) {
			continue
		}
		if err := s.saveImageAndProductImage(ctx, tx, p.ID, pi, p); err != nil {
			// tx.Rollback()
			// return false
			continue
		}
	}

	return true
}

// SaveMeiTuanProducts 单商品独立事务批量保存美团商品及关联图片
// 参数: record - 待保存的美团商品数据列表（包含商品信息及图片列表）
// 返回: 成功保存的商品记录数（仅统计事务提交成功的记录）
func (s *ProductService) SaveMeiTuanProducts(record []*beans.ProductMeiTuanBean) int64 {
	var successCount int64

	for _, bean := range record {
		// 1. 检查商品是否已存在，存在则跳过
		if s.IsExitsMeiTuan(bean.Product) {
			continue
		}

		// 2. 单商品独立事务：保存商品及关联图片
		// 注意：事务闭包返回error时会自动回滚，返回nil则自动提交
		err := s.db.Transaction(func(tx *gorm.DB) error {
			// 2.1 保存商品主记录
			if err := tx.Create(bean.Product).Error; err != nil {
				return fmt.Errorf("保存商品失败: %w", err)
			}

			// 2.2 绑定商品ID到图片记录（批量操作替代循环赋值）
			for i := range bean.ImageList {
				bean.ImageList[i].ProductID = bean.Product.ID
			}

			// 2.3 批量保存关联图片（空切片时自动跳过）
			if err := tx.CreateInBatches(bean.ImageList, 100).Error; err != nil {
				return fmt.Errorf("保存商品图片失败: %w", err)
			}

			return nil // 事务提交
		})

		// 3. 仅当事务成功时计数
		if err == nil {
			successCount++
		}
	}

	return successCount
}

// IsExits checks if a product already exists based on certain criteria.
func (s *ProductService) IsExits(record *models.LibraryProduct) bool {
	if record == nil {
		return false
	}

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

	if record.Source != "" {
		q = q.Where(m.Source.Eq(record.Source))
	}

	if record.Barcode != "" {
		q = q.Where(m.Barcode.Eq(record.Barcode))
	}

	if record.Name != "" {
		q = q.Where(m.Name.Eq(record.Name))
	}

	cnt, err := q.Count()
	if err != nil {
		log.Printf("查询商品数量失败: %v", err)
		return false
	}

	return cnt > 0
}

// IsExitsMeiTuan 检查美团商品是否已存在
// 参数: record - 待检查的商品记录
// 返回: 存在返回true，否则返回false
func (s *ProductService) IsExitsMeiTuan(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.Title != "" {
		q = q.Where(m.Title.Eq(record.Title))
	} else {
		// 无有效查询条件
		return false
	}

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

	return cnt > 0
}

func (s *ProductService) IsExitsProductImage(productID uint64, imageURL string) bool {
	if productID <= 0 || imageURL == "" {
		return false
	}

	m := mapper.LibraryProductImage
	q := m.Select(m.ID).Where(m.ProductID.Eq(productID), m.ImageURL.Eq(imageURL))

	cnt, err := q.Count()
	if err != nil {
		log.Printf("查询商品数量失败: %v", err)
		return false
	}

	return cnt > 0
}
