package seeder

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"

	"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"

	"github.com/tidwall/gjson"
	"gorm.io/gorm"
)

// SeedPigNutrientRequirements 先严格校验JSON源文件，然后以“有则跳过”的模式播种数据。
func SeedPigNutrientRequirements(ctx context.Context, tx *gorm.DB, jsonData []byte) error {
	logger := logs.GetLogger(ctx)

	// 检查 PigBreed 表是否为空，如果非空则跳过播种
	isEmpty, err := isTableEmpty(tx, &models.PigBreed{})
	if err != nil {
		return fmt.Errorf("检查 PigBreed 表是否为空失败: %w", err)
	}
	if !isEmpty {
		logger.Info("已存在猪种数据, 跳过数据播种")
		return nil
	}

	// 1. 严格校验JSON文件，检查内部重复键
	if err := validateAndParsePigNutrientRequirementJSON(jsonData); err != nil {
		return fmt.Errorf("JSON源文件校验失败: %w", err)
	}

	// 2. 解析简介信息
	descriptionsNode := gjson.GetBytes(jsonData, "descriptions")
	pigBreedDescriptions := make(map[string]models.PigBreed)
	pigAgeStageDescriptions := make(map[string]models.PigAgeStage)
	pigTypeDescriptions := make(map[string]map[string]models.PigType)

	if descriptionsNode.Exists() {
		// 解析 pig_breeds 描述
		descriptionsNode.Get("pig_breeds").ForEach(func(key, value gjson.Result) bool {
			var pb models.PigBreed
			pb.Name = key.String()
			pb.Description = value.Get("description").String()
			pb.ParentInfo = value.Get("parent_info").String()
			pb.AppearanceFeatures = value.Get("appearance_features").String()
			pb.BreedAdvantages = value.Get("breed_advantages").String()
			pb.BreedDisadvantages = value.Get("breed_disadvantages").String()
			pigBreedDescriptions[key.String()] = pb
			return true
		})

		// 解析 pig_age_stages 描述
		descriptionsNode.Get("pig_age_stages").ForEach(func(key, value gjson.Result) bool {
			var pas models.PigAgeStage
			pas.Name = key.String()
			pas.Description = value.String()
			pigAgeStageDescriptions[key.String()] = pas
			return true
		})

		// 解析 pig_breed_age_stages (PigType) 描述
		descriptionsNode.Get("pig_breed_age_stages").ForEach(func(breedKey, breedValue gjson.Result) bool {
			if _, ok := pigTypeDescriptions[breedKey.String()]; !ok {
				pigTypeDescriptions[breedKey.String()] = make(map[string]models.PigType)
			}
			breedValue.ForEach(func(ageStageKey, ageStageValue gjson.Result) bool {
				var pt models.PigType
				pt.Description = ageStageValue.Get("description").String()
				pt.DailyFeedIntake = float32(ageStageValue.Get("daily_feed_intake").Float())
				pt.DailyGainWeight = float32(ageStageValue.Get("daily_gain_weight").Float())
				pt.MinDays = uint32(ageStageValue.Get("min_days").Uint())
				pt.MaxDays = uint32(ageStageValue.Get("max_days").Uint())
				pt.MinWeight = float32(ageStageValue.Get("min_weight").Float())
				pt.MaxWeight = float32(ageStageValue.Get("max_weight").Float())
				pigTypeDescriptions[breedKey.String()][ageStageKey.String()] = pt
				return true
			})
			return true
		})
	}

	// 3. 将通过校验的、干净的数据写入数据库
	dataNode := gjson.GetBytes(jsonData, "data")
	dataNode.ForEach(func(breedKey, breedValue gjson.Result) bool {
		breedName := breedKey.String()
		var pigBreed models.PigBreed
		// 查找或创建 PigBreed
		pbDesc := pigBreedDescriptions[breedName]
		err = tx.Where(models.PigBreed{Name: breedName}).
			FirstOrCreate(&pigBreed, models.PigBreed{
				Name:               breedName,
				Description:        pbDesc.Description,
				ParentInfo:         pbDesc.ParentInfo,
				AppearanceFeatures: pbDesc.AppearanceFeatures,
				BreedAdvantages:    pbDesc.BreedAdvantages,
				BreedDisadvantages: pbDesc.BreedDisadvantages,
			}).Error
		if err != nil {
			return false
		}

		breedValue.ForEach(func(ageStageKey, ageStageValue gjson.Result) bool {
			ageStageName := ageStageKey.String()
			var pigAgeStage models.PigAgeStage
			// 查找或创建 PigAgeStage
			pasDesc := pigAgeStageDescriptions[ageStageName]
			err = tx.Where(models.PigAgeStage{Name: ageStageName}).
				FirstOrCreate(&pigAgeStage, models.PigAgeStage{
					Name:        ageStageName,
					Description: pasDesc.Description,
				}).Error

			if err != nil {
				return false
			}

			var pigType models.PigType
			// 查找或创建 PigType
			ptDesc := pigTypeDescriptions[breedName][ageStageName]
			err = tx.Where(models.PigType{BreedID: pigBreed.ID, AgeStageID: pigAgeStage.ID}).
				FirstOrCreate(&pigType, models.PigType{
					BreedID:         pigBreed.ID,
					AgeStageID:      pigAgeStage.ID,
					Description:     ptDesc.Description,
					DailyFeedIntake: ptDesc.DailyFeedIntake,
					DailyGainWeight: ptDesc.DailyGainWeight,
					MinDays:         ptDesc.MinDays,
					MaxDays:         ptDesc.MaxDays,
					MinWeight:       ptDesc.MinWeight,
					MaxWeight:       ptDesc.MaxWeight,
				}).Error
			if err != nil {
				return false
			}

			ageStageValue.ForEach(func(nutrientKey, nutrientValue gjson.Result) bool {
				nutrientName := nutrientKey.String()
				minReq := float32(nutrientValue.Get("min_requirement").Float())
				maxReq := float32(nutrientValue.Get("max_requirement").Float())

				var nutrient models.Nutrient
				// 查找或创建 Nutrient (这里假设 Nutrient 已经在 SeedNutrients 中处理，但为了健壮性，再次 FirstOrCreate)
				err = tx.Where(models.Nutrient{Name: nutrientName}).
					FirstOrCreate(&nutrient, models.Nutrient{
						Name: nutrientName,
						// Description 字段在 nutrient seeder 中处理，这里不设置
					}).Error
				if err != nil {
					return false
				}

				linkData := models.PigNutrientRequirement{
					PigTypeID:      pigType.ID,
					NutrientID:     nutrient.ID,
					MinRequirement: minReq,
					MaxRequirement: maxReq,
				}
				// 使用 FirstOrCreate 确保关联的唯一性
				err = tx.Where(models.PigNutrientRequirement{
					PigTypeID:  pigType.ID,
					NutrientID: nutrient.ID,
				}).FirstOrCreate(&linkData, linkData).Error
				if err != nil {
					return false
				}
				return true
			})
			return err == nil // 如果内部遍历有错误，则停止外部遍历
		})
		return err == nil // 如果内部遍历有错误，则停止外部遍历
	})
	return err // 返回捕获到的错误
}

// validateAndParsePigNutrientRequirementJSON 严格校验猪营养需求JSON文件
func validateAndParsePigNutrientRequirementJSON(jsonData []byte) error {
	dataNode := gjson.GetBytes(jsonData, "data")
	if !dataNode.Exists() {
		return errors.New("JSON文件中缺少 'data' 字段")
	}
	if !dataNode.IsObject() {
		return errors.New("'data' 字段必须是一个JSON对象")
	}

	decoder := json.NewDecoder(bytes.NewReader([]byte(dataNode.Raw)))
	decoder.UseNumber()

	if t, err := decoder.Token(); err != nil || t != json.Delim('{') {
		return fmt.Errorf("'data' 字段解析起始符失败: %v", err)
	}

	seenBreeds := make(map[string]bool)

	for decoder.More() {
		// 解析 PigBreed 名称
		t, err := decoder.Token()
		if err != nil {
			return fmt.Errorf("解析猪品种名称失败: %w", err)
		}
		breedName := t.(string)
		if seenBreeds[breedName] {
			return fmt.Errorf("猪品种名称 '%s' 重复", breedName)
		}
		seenBreeds[breedName] = true

		// 解析该品种的年龄阶段对象
		if t, err := decoder.Token(); err != nil || t != json.Delim('{') {
			return fmt.Errorf("期望猪品种 '%s' 的值是一个JSON对象", breedName)
		}

		seenAgeStages := make(map[string]bool)

		for decoder.More() {
			// 解析 PigAgeStage 名称
			t, err := decoder.Token()
			if err != nil {
				return fmt.Errorf("在猪品种 '%s' 中解析年龄阶段名称失败: %w", breedName, err)
			}
			ageStageName := t.(string)
			if seenAgeStages[ageStageName] {
				return fmt.Errorf("在猪品种 '%s' 中, 年龄阶段名称 '%s' 重复", breedName, ageStageName)
			}
			seenAgeStages[ageStageName] = true

			// 解析该年龄阶段的营养成分对象
			if t, err := decoder.Token(); err != nil || t != json.Delim('{') {
				return fmt.Errorf("期望年龄阶段 '%s' 的值是一个JSON对象", ageStageName)
			}

			seenNutrients := make(map[string]bool)

			for decoder.More() {
				// 解析 Nutrient 名称
				t, err := decoder.Token()
				if err != nil {
					return fmt.Errorf("在年龄阶段 '%s' 中解析营养素名称失败: %w", ageStageName, err)
				}
				nutrientName := t.(string)
				if seenNutrients[nutrientName] {
					return fmt.Errorf("在年龄阶段 '%s' 中, 营养素名称 '%s' 重复", ageStageName, nutrientName)
				}
				seenNutrients[nutrientName] = true

				// 解析 min_requirement 和 max_requirement 对象
				if t, err := decoder.Token(); err != nil || t != json.Delim('{') {
					return fmt.Errorf("期望营养素 '%s' 的值是一个JSON对象", nutrientName)
				}

				for decoder.More() {
					t, err := decoder.Token()
					if err != nil {
						return fmt.Errorf("解析营养素 '%s' 的需求键失败: %w", nutrientName, err)
					}
					// key := t.(string) // 校验时不需要使用 key 的值

					t, err = decoder.Token()
					if err != nil {
						return fmt.Errorf("解析营养素 '%s' 的需求值失败: %w", nutrientName, err)
					}
					if _, ok := t.(json.Number); !ok {
						return fmt.Errorf("期望营养素 '%s' 的需求值是数字, 但实际得到的类型是 %T, 值为 '%v'", nutrientName, t, t)
					}
				}
				if t, err := decoder.Token(); err != nil || t != json.Delim('}') {
					return fmt.Errorf("解析营养素 '%s' 的值结束符 '}' 失败", nutrientName)
				}
			}
			if t, err := decoder.Token(); err != nil || t != json.Delim('}') {
				return fmt.Errorf("解析年龄阶段 '%s' 的值结束符 '}' 失败", ageStageName)
			}
		}
		if t, err := decoder.Token(); err != nil || t != json.Delim('}') {
			return fmt.Errorf("解析猪品种 '%s' 的值结束符 '}' 失败", breedName)
		}
	}
	return nil
}
