package snapshot

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"time"

	"bindbox-game/internal/repository/mysql"
	"bindbox-game/internal/repository/mysql/model"
)

// UserStateSnapshot 用户状态快照
type UserStateSnapshot struct {
	SnapshotTime   time.Time       `json:"snapshot_time"`
	User           *UserInfo       `json:"user"`
	Points         *PointsInfo     `json:"points"`
	Coupons        []*CouponInfo   `json:"coupons"`
	ItemCards      []*ItemCardInfo `json:"item_cards"`
	InventoryCount int64           `json:"inventory_count"`
}

// UserInfo 用户基本信息
type UserInfo struct {
	ID       int64  `json:"id"`
	Nickname string `json:"nickname"`
	Mobile   string `json:"mobile"`
}

// PointsInfo 积分信息
type PointsInfo struct {
	Balance int64 `json:"balance"`
	Version int32 `json:"version"`
}

// CouponInfo 优惠券信息
type CouponInfo struct {
	UserCouponID  int64     `json:"user_coupon_id"`
	CouponID      int64     `json:"coupon_id"`
	CouponName    string    `json:"coupon_name"`
	Status        int32     `json:"status"`
	BalanceAmount int64     `json:"balance_amount"`
	ValidEnd      time.Time `json:"valid_end"`
}

// ItemCardInfo 道具卡信息
type ItemCardInfo struct {
	UserItemCardID int64     `json:"user_item_card_id"`
	CardID         int64     `json:"card_id"`
	CardName       string    `json:"card_name"`
	Status         int32     `json:"status"`
	ValidEnd       time.Time `json:"valid_end"`
}

// SnapshotDiff 快照差异
type SnapshotDiff struct {
	PointsChanged  int64           `json:"points_changed"`
	CouponsUsed    []*CouponInfo   `json:"coupons_used"`
	ItemCardsUsed  []*ItemCardInfo `json:"item_cards_used"`
	InventoryAdded int64           `json:"inventory_added"`
}

// Service 快照服务
type Service interface {
	// CaptureUserState 采集用户当前状态
	CaptureUserState(ctx context.Context, userID int64) (*UserStateSnapshot, error)
	// SaveSnapshot 保存快照
	SaveSnapshot(ctx context.Context, orderID int64, orderNo string, userID int64, snapshotType int32, snapshot *UserStateSnapshot) error
	// GetSnapshotsByOrderID 获取订单快照
	GetSnapshotsByOrderID(ctx context.Context, orderID int64) (*model.OrderSnapshots, *model.OrderSnapshots, error)
	// CompareSnapshots 对比快照差异
	CompareSnapshots(before, after *UserStateSnapshot) *SnapshotDiff
}

type service struct {
	db mysql.Repo
}

// NewService 创建快照服务
func NewService(db mysql.Repo) Service {
	return &service{db: db}
}

// CaptureUserState 采集用户当前状态
func (s *service) CaptureUserState(ctx context.Context, userID int64) (*UserStateSnapshot, error) {
	snapshot := &UserStateSnapshot{
		SnapshotTime: time.Now(),
	}

	// 1. 查询用户基本信息
	var user model.Users
	if err := s.db.GetDbR().WithContext(ctx).Where("id = ?", userID).First(&user).Error; err == nil {
		snapshot.User = &UserInfo{
			ID:       user.ID,
			Nickname: user.Nickname,
			Mobile:   user.Mobile,
		}
	}

	// 2. 查询用户积分
	var points model.UserPoints
	if err := s.db.GetDbR().WithContext(ctx).Where("user_id = ?", userID).First(&points).Error; err == nil {
		snapshot.Points = &PointsInfo{
			Balance: points.Points,
			Version: points.Version,
		}
	} else {
		snapshot.Points = &PointsInfo{Balance: 0, Version: 0}
	}

	// 3. 查询未使用的优惠券
	var userCoupons []model.UserCoupons
	s.db.GetDbR().WithContext(ctx).Where("user_id = ? AND status = 1", userID).Find(&userCoupons)

	if len(userCoupons) > 0 {
		couponIDs := make([]int64, 0, len(userCoupons))
		for _, uc := range userCoupons {
			couponIDs = append(couponIDs, uc.CouponID)
		}

		var systemCoupons []model.SystemCoupons
		s.db.GetDbR().WithContext(ctx).Where("id IN ?", couponIDs).Find(&systemCoupons)

		couponNameMap := make(map[int64]string)
		for _, sc := range systemCoupons {
			couponNameMap[sc.ID] = sc.Name
		}

		for _, uc := range userCoupons {
			snapshot.Coupons = append(snapshot.Coupons, &CouponInfo{
				UserCouponID:  uc.ID,
				CouponID:      uc.CouponID,
				CouponName:    couponNameMap[uc.CouponID],
				Status:        uc.Status,
				BalanceAmount: uc.BalanceAmount,
				ValidEnd:      uc.ValidEnd,
			})
		}
	}

	// 4. 查询未使用的道具卡
	var userItemCards []model.UserItemCards
	s.db.GetDbR().WithContext(ctx).Where("user_id = ? AND status = 1", userID).Find(&userItemCards)

	if len(userItemCards) > 0 {
		cardIDs := make([]int64, 0, len(userItemCards))
		for _, uc := range userItemCards {
			cardIDs = append(cardIDs, uc.CardID)
		}

		var systemCards []model.SystemItemCards
		s.db.GetDbR().WithContext(ctx).Where("id IN ?", cardIDs).Find(&systemCards)

		cardNameMap := make(map[int64]string)
		for _, sc := range systemCards {
			cardNameMap[sc.ID] = sc.Name
		}

		for _, uc := range userItemCards {
			snapshot.ItemCards = append(snapshot.ItemCards, &ItemCardInfo{
				UserItemCardID: uc.ID,
				CardID:         uc.CardID,
				CardName:       cardNameMap[uc.CardID],
				Status:         uc.Status,
				ValidEnd:       uc.ValidEnd,
			})
		}
	}

	// 5. 查询资产数量
	var inventoryCount int64
	s.db.GetDbR().WithContext(ctx).Model(&model.UserInventory{}).Where("user_id = ? AND status = 1", userID).Count(&inventoryCount)
	snapshot.InventoryCount = inventoryCount

	return snapshot, nil
}

// SaveSnapshot 保存快照
func (s *service) SaveSnapshot(ctx context.Context, orderID int64, orderNo string, userID int64, snapshotType int32, snapshot *UserStateSnapshot) error {
	data, err := json.Marshal(snapshot)
	if err != nil {
		return err
	}

	// 计算hash
	hash := sha256.Sum256(data)
	hashStr := hex.EncodeToString(hash[:])

	record := &model.OrderSnapshots{
		OrderID:      orderID,
		OrderNo:      orderNo,
		UserID:       userID,
		SnapshotType: snapshotType,
		SnapshotData: string(data),
		SnapshotHash: hashStr,
	}

	return s.db.GetDbW().WithContext(ctx).Create(record).Error
}

// GetSnapshotsByOrderID 获取订单快照
func (s *service) GetSnapshotsByOrderID(ctx context.Context, orderID int64) (*model.OrderSnapshots, *model.OrderSnapshots, error) {
	var snapshots []model.OrderSnapshots
	if err := s.db.GetDbR().WithContext(ctx).Where("order_id = ?", orderID).Order("snapshot_type ASC").Find(&snapshots).Error; err != nil {
		return nil, nil, err
	}

	var before, after *model.OrderSnapshots
	for i := range snapshots {
		if snapshots[i].SnapshotType == 1 {
			before = &snapshots[i]
		} else if snapshots[i].SnapshotType == 2 {
			after = &snapshots[i]
		}
	}

	return before, after, nil
}

// CompareSnapshots 对比快照差异
func (s *service) CompareSnapshots(before, after *UserStateSnapshot) *SnapshotDiff {
	diff := &SnapshotDiff{}

	// 积分差异
	if before.Points != nil && after.Points != nil {
		diff.PointsChanged = after.Points.Balance - before.Points.Balance
	}

	// 优惠券使用情况（消费前有，消费后没有或状态变化）
	afterCouponMap := make(map[int64]*CouponInfo)
	for _, c := range after.Coupons {
		afterCouponMap[c.UserCouponID] = c
	}
	for _, c := range before.Coupons {
		if _, ok := afterCouponMap[c.UserCouponID]; !ok {
			// 消费后不存在，说明被使用了
			diff.CouponsUsed = append(diff.CouponsUsed, c)
		} else if afterCouponMap[c.UserCouponID].Status != c.Status {
			// 状态变化，说明被使用了
			diff.CouponsUsed = append(diff.CouponsUsed, c)
		}
	}

	// 道具卡使用情况
	afterCardMap := make(map[int64]*ItemCardInfo)
	for _, c := range after.ItemCards {
		afterCardMap[c.UserItemCardID] = c
	}
	for _, c := range before.ItemCards {
		if _, ok := afterCardMap[c.UserItemCardID]; !ok {
			diff.ItemCardsUsed = append(diff.ItemCardsUsed, c)
		} else if afterCardMap[c.UserItemCardID].Status != c.Status {
			diff.ItemCardsUsed = append(diff.ItemCardsUsed, c)
		}
	}

	// 资产增加
	diff.InventoryAdded = after.InventoryCount - before.InventoryCount

	return diff
}
