package auth

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
)

// User 用户数据
type User struct {
	ID              string           `json:"id"`
	Username        string           `json:"username"`
	PasswordHash    string           `json:"-"` // 不返回给客户端
	CreatedAt       int64            `json:"created_at"`
	Level           int              `json:"level"`
	Exp             int              `json:"exp"`
	Diamonds        int              `json:"diamonds"`
	RedstoneCoins   int64            `json:"redstone_coins"`
	GoldCoins       int              `json:"gold_coins"`
	LastLoginDate   string           `json:"last_login_date"`
	Inventory       map[string]int   `json:"inventory"`        // itemId → count
	EquippedItem    string           `json:"equipped_item"`    // 当前装备的道具ID
	SpeedBoostUntil int64            `json:"speed_boost_until"` // 速度加成到期时间(unix)
	PurchaseHistory []PurchaseRecord `json:"purchase_history"` // 最近50条购买记录
}

// PurchaseRecord 购买记录
type PurchaseRecord struct {
	ItemID    string `json:"item_id"`
	ItemName  string `json:"item_name"`
	Currency  string `json:"currency"`
	Amount    int64  `json:"amount"`
	Timestamp int64  `json:"timestamp"`
}

// UserStore 内存用户存储 (后续可替换为 PostgreSQL)
type UserStore struct {
	mu    sync.RWMutex
	users map[string]*User // key = username (lowercase)
}

func NewUserStore() *UserStore {
	return &UserStore{users: make(map[string]*User)}
}

func (s *UserStore) Create(username, password string) (*User, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	if _, exists := s.users[username]; exists {
		return nil, errors.New("用户名已存在")
	}

	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return nil, fmt.Errorf("密码加密失败: %w", err)
	}

	now := time.Now()
	user := &User{
		ID:              fmt.Sprintf("u_%d", now.UnixNano()),
		Username:        username,
		PasswordHash:    string(hash),
		CreatedAt:       now.Unix(),
		Level:           1,
		Exp:             0,
		Diamonds:        20,
		RedstoneCoins:   3000,
		GoldCoins:       1,
		LastLoginDate:   "", // 留空：注册当天可正常签到领奖
		Inventory:       make(map[string]int),
		PurchaseHistory: []PurchaseRecord{},
	}
	s.users[username] = user
	return user, nil
}

func (s *UserStore) GetByUsername(username string) (*User, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	u, ok := s.users[username]
	return u, ok
}

func (s *UserStore) GetByID(id string) (*User, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	for _, u := range s.users {
		if u.ID == id {
			return u, true
		}
	}
	return nil, false
}

func (s *UserStore) VerifyPassword(username, password string) (*User, error) {
	user, ok := s.GetByUsername(username)
	if !ok {
		return nil, errors.New("用户不存在")
	}
	if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)); err != nil {
		return nil, errors.New("密码错误")
	}
	return user, nil
}

// DailyLogin 每日登录奖励。返回奖励详情和是否已领取。
func (s *UserStore) DailyLogin(userID string) (map[string]interface{}, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	var user *User
	for _, u := range s.users {
		if u.ID == userID {
			user = u
			break
		}
	}
	if user == nil {
		return nil, errors.New("用户不存在")
	}

	today := time.Now().Format("2006-01-02")
	if user.LastLoginDate == today {
		return map[string]interface{}{
			"claimed": true,
			"message": "今日已领取",
		}, nil
	}

	// 发放奖励
	const rewardDiamonds = 20
	const rewardRedstoneCoins = 3000
	const rewardGoldCoins = 1

	user.Diamonds += rewardDiamonds
	user.RedstoneCoins += rewardRedstoneCoins
	user.GoldCoins += rewardGoldCoins
	user.LastLoginDate = today

	return map[string]interface{}{
		"claimed":      false,
		"message":      "领取成功",
		"diamonds":     rewardDiamonds,
		"redstone":     rewardRedstoneCoins,
		"gold":         rewardGoldCoins,
		"total_diamonds":     user.Diamonds,
		"total_redstone":     user.RedstoneCoins,
		"total_gold":         user.GoldCoins,
	}, nil
}

// SpendCurrency 消费货币，返回成功或余额不足错误
func (s *UserStore) SpendCurrency(userID, currency string, amount int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	var user *User
	for _, u := range s.users {
		if u.ID == userID {
			user = u
			break
		}
	}
	if user == nil {
		return errors.New("用户不存在")
	}

	switch currency {
	case "diamonds":
		if user.Diamonds < int(amount) {
			return fmt.Errorf("钻石不足，当前: %d，需要: %d", user.Diamonds, amount)
		}
		user.Diamonds -= int(amount)
	case "redstone_coins":
		if user.RedstoneCoins < amount {
			return fmt.Errorf("红石币不足，当前: %d，需要: %d", user.RedstoneCoins, amount)
		}
		user.RedstoneCoins -= amount
	case "gold_coins":
		if user.GoldCoins < int(amount) {
			return fmt.Errorf("金币不足，当前: %d，需要: %d", user.GoldCoins, amount)
		}
		user.GoldCoins -= int(amount)
	default:
		return fmt.Errorf("未知货币类型: %s", currency)
	}
	return nil
}

// BuyItem 购买商品 (货币扣款 + 库存追踪 + 交易记录)
func (s *UserStore) BuyItem(userID, itemID, itemName, currency string, amount int64, quantity int) (map[string]interface{}, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	var user *User
	for _, u := range s.users { if u.ID == userID { user = u; break } }
	if user == nil { return nil, errors.New("用户不存在") }
	switch currency {
	case "diamonds": if user.Diamonds < int(amount) { return nil, fmt.Errorf("钻石不足") }; user.Diamonds -= int(amount)
	case "redstone_coins": if user.RedstoneCoins < amount { return nil, fmt.Errorf("红石币不足") }; user.RedstoneCoins -= amount
	case "gold_coins": if user.GoldCoins < int(amount) { return nil, fmt.Errorf("金币不足") }; user.GoldCoins -= int(amount)
	default: return nil, fmt.Errorf("未知货币")
	}
	if user.Inventory == nil { user.Inventory = make(map[string]int) }
	user.Inventory[itemID] += quantity
	if itemID == "speed_boost" { user.SpeedBoostUntil = time.Now().Unix() + 3600 }
	rec := PurchaseRecord{ItemID: itemID, ItemName: itemName, Currency: currency, Amount: amount, Timestamp: time.Now().Unix()}
	user.PurchaseHistory = append([]PurchaseRecord{rec}, user.PurchaseHistory...)
	if len(user.PurchaseHistory) > 50 { user.PurchaseHistory = user.PurchaseHistory[:50] }
	return map[string]interface{}{"message": "购买成功", "item_id": itemID, "quantity": quantity, "user": userToMap(user)}, nil
}

// UseItem 使用道具
func (s *UserStore) UseItem(userID, itemID string) (map[string]interface{}, error) {
	s.mu.Lock(); defer s.mu.Unlock()
	var user *User
	for _, u := range s.users { if u.ID == userID { user = u; break } }
	if user == nil { return nil, errors.New("用户不存在") }
	if user.Inventory == nil || user.Inventory[itemID] <= 0 { return nil, errors.New("道具数量不足") }
	user.Inventory[itemID]--
	msg := "使用成功"
	switch itemID {
	case "speed_boost":
		user.SpeedBoostUntil = time.Now().Unix() + 3600
		user.EquippedItem = itemID
		msg = "速度加成已激活(1小时)"
	case "exp_boost":
		user.Exp += 500
		if user.Exp >= user.Level*1000 {
			user.Level++
			user.Exp -= (user.Level - 1) * 1000
			msg = fmt.Sprintf("升级! Lv.%d", user.Level)
		} else {
			msg = "获得500经验值"
		}
	case "diamond_pack":
		user.Diamonds += 10
		msg = "获得10钻石"
	case "gold_pack":
		user.GoldCoins += 5
		msg = "获得5金币"
	case "rs_pack":
		user.RedstoneCoins += 10000
		msg = "获得10000红石币"
	}
	return map[string]interface{}{"message": msg, "user": userToMap(user)}, nil
}

// userToMap 将 User 转换为返回给客户端的 map
func userToMap(u *User) map[string]interface{} {
	inv := u.Inventory
	if inv == nil { inv = make(map[string]int) }
	hist := u.PurchaseHistory
	if hist == nil { hist = []PurchaseRecord{} }
	return map[string]interface{}{
		"id":               u.ID,
		"username":         u.Username,
		"level":            u.Level,
		"exp":              u.Exp,
		"diamonds":         u.Diamonds,
		"redstone_coins":   u.RedstoneCoins,
		"gold_coins":       u.GoldCoins,
		"last_login_date":  u.LastLoginDate,
		"created_at":       u.CreatedAt,
		"inventory":        inv,
		"equipped_item":    u.EquippedItem,
		"speed_boost_until": u.SpeedBoostUntil,
		"purchase_history": hist,
	}
}

// ==================== JWT ====================

type JWTManager struct {
	secretKey []byte
	expires   time.Duration
}

func NewJWTManager(secret string) *JWTManager {
	return &JWTManager{
		secretKey: []byte(secret),
		expires:   24 * time.Hour,
	}
}

type Claims struct {
	UserID   string `json:"uid"`
	Username string `json:"username"`
	jwt.RegisteredClaims
}

func (m *JWTManager) Generate(user *User) (string, error) {
	claims := &Claims{
		UserID:   user.ID,
		Username: user.Username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(m.expires)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(m.secretKey)
}

func (m *JWTManager) Verify(tokenStr string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(t *jwt.Token) (interface{}, error) {
		if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
		}
		return m.secretKey, nil
	})
	if err != nil {
		return nil, err
	}
	claims, ok := token.Claims.(*Claims)
	if !ok || !token.Valid {
		return nil, errors.New("invalid token")
	}
	return claims, nil
}
