package logic

import (
	"context"
	"errors"
	"time"

	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
	plantModel "sundynix-micro-go/app/plant/model"
	"sundynix-micro-go/app/plant/rpc/internal/svc"
	"sundynix-micro-go/app/plant/rpc/plant"
)

type CompleteTaskLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewCompleteTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CompleteTaskLogic {
	return &CompleteTaskLogic{ctx: ctx, svcCtx: svcCtx, Logger: logx.WithContext(ctx)}
}

const taskReward = int64(50)

func (l *CompleteTaskLogic) CompleteTask(in *plant.CompleteTaskReq) (*plant.TaskCompletionResult, error) {
	var result plant.TaskCompletionResult
	err := l.svcCtx.DB.Transaction(func(tx *gorm.DB) error {
		// 1. 查任务
		var task plantModel.CareTask
		if err := tx.Set("gorm:query_option", "FOR UPDATE").
			Where("id = ? AND user_id = ?", in.TaskId, in.UserId).First(&task).Error; err != nil {
			return err
		}
		if task.Status != 1 {
			return errors.New("任务已完成或已过期，不能重复完成")
		}
		// 2. 标记完成
		now := time.Now()
		if err := tx.Model(&task).Updates(map[string]interface{}{
			"status": 2, "completed_at": now,
		}).Error; err != nil {
			return err
		}
		// 3. 查计划，生成下个周期任务
		var plan plantModel.CarePlan
		if err := tx.Where("id = ?", task.PlanID).First(&plan).Error; err != nil {
			return err
		}
		today := time.Now()
		todayZero := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, today.Location())
		nextDue := todayZero.AddDate(0, 0, plan.Period)
		newTask := plantModel.CareTask{
			UserID: plan.UserID, PlantID: plan.PlantID, PlanID: plan.ID,
			Name: plan.Name, Icon: plan.Icon, TargetAction: plan.TargetAction,
			DueDate: nextDue, Status: 1,
		}
		if err := tx.Create(&newTask).Error; err != nil {
			return err
		}
		// 4. 保存养护记录
		record := plantModel.CareRecord{
			UserID: plan.UserID, PlantID: plan.PlantID, PlanID: plan.ID,
			Name: plan.Name, Icon: plan.Icon, Remark: in.Remark,
		}
		if err := tx.Create(&record).Error; err != nil {
			return err
		}
		// 5. 查用户 profile（加锁）
		var profile plantModel.UserProfile
		if err := tx.Set("gorm:query_option", "FOR UPDATE").
			Where("user_id = ?", in.UserId).First(&profile).Error; err != nil {
			return err
		}
		fieldMap := map[string]string{
			"ACT_WATER": "water_count", "ACT_FERTILIZE": "fertilize_count",
			"ACT_REPOT": "repot_count", "ACT_PRUNE": "prune_count",
		}
		col, ok := fieldMap[task.TargetAction]
		if !ok {
			col = "care_count"
		}
		newTotal := profile.TotalSunlight + taskReward
		// 5.1 等级判定
		var latestLevel plantModel.LevelConfig
		levelErr := tx.Where("min_sunlight <= ?", newTotal).
			Order("min_sunlight DESC").First(&latestLevel).Error
		if levelErr != nil {
			if errors.Is(levelErr, gorm.ErrRecordNotFound) {
				// 没有等级配置，跳过等级相关逻辑
				result.IsLevelUp = false
				result.RewardSunlight = taskReward
				// 仍要更新阳光值
				profileData := map[string]interface{}{
					col:                gorm.Expr(col + " + 1"),
					"current_sunlight": profile.CurrentSunlight + taskReward,
					"total_sunlight":   newTotal,
				}
				if err := tx.Model(&plantModel.UserProfile{}).
					Where("user_id = ?", in.UserId).Updates(profileData).Error; err != nil {
					return err
				}
				return nil // 跳过后续等级/徽章逻辑
			}
			return errors.New("等级配置异常")
		}
		result.IsLevelUp = (latestLevel.ID != profile.LevelID)
		result.CurrentLevel = &plant.LevelConfigInfo{
			Id: latestLevel.ID, Level: int32(latestLevel.Level),
			Title: latestLevel.Title, MinSunlight: latestLevel.MinSunlight,
		}
		result.RewardSunlight = taskReward
		// 5.2 更新 profile
		profileData := map[string]interface{}{
			col:                gorm.Expr(col + " + 1"),
			"current_sunlight": profile.CurrentSunlight + taskReward,
			"total_sunlight":   newTotal,
			"level_id":         latestLevel.ID,
		}
		if err := tx.Model(&plantModel.UserProfile{}).
			Where("user_id = ?", in.UserId).Updates(profileData).Error; err != nil {
			return err
		}
		// 6. 徽章判定
		actionValMap := map[string]int64{
			"ACT_WATER": profile.WaterCount + 1, "ACT_FERTILIZE": profile.FertilizeCount + 1,
			"ACT_REPOT": profile.RepotCount + 1, "ACT_PRUNE": profile.PruneCount + 1,
		}
		currentVal := actionValMap[task.TargetAction]
		var ownedIds []string
		tx.Model(&plantModel.UserBadge{}).Where("user_id = ?", in.UserId).Pluck("badge_id", &ownedIds)
		ownedMap := make(map[string]bool)
		for _, id := range ownedIds {
			ownedMap[id] = true
		}
		var badgeConfigs []plantModel.BadgeConfig
		tx.Where("target_action = ?", task.TargetAction).Find(&badgeConfigs)
		var bestBadge *plantModel.BadgeConfig
		for i := range badgeConfigs {
			bc := &badgeConfigs[i]
			if !ownedMap[bc.ID] && currentVal >= bc.Threshold {
				if bestBadge == nil || bc.Tier > bestBadge.Tier {
					bestBadge = bc
				}
			}
		}
		if bestBadge != nil {
			ub := plantModel.UserBadge{UserID: in.UserId, BadgeID: bestBadge.ID}
			if err := tx.Create(&ub).Error; err != nil {
				return err
			}
			tx.Model(&plantModel.UserProfile{}).Where("user_id = ?", in.UserId).
				UpdateColumn("current_sunlight", gorm.Expr("current_sunlight + ?", bestBadge.RewardSunlight))
			result.IsGetBadge = true
			result.NewBadge = &plant.BadgeConfigInfo{
				Id: bestBadge.ID, Name: bestBadge.Name, Dimension: bestBadge.Dimension,
				Tier: int32(bestBadge.Tier), RewardSunlight: bestBadge.RewardSunlight,
			}
		}
		return nil
	})
	return &result, err
}
