package handlers

import (
	"context"
	"errors"
	"net/http"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"

	"yh_web/server/config"
	"yh_web/server/models"
	"yh_web/server/utils"

	"github.com/gin-gonic/gin"
)

func GetUsers(c *gin.Context) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	coll := config.GetDB(config.DBName).Collection("users")

	page := 1
	pageSize := 20
	if p := c.Query("page"); p != "" {
		if v, err := parseInt(p); err == nil && v > 0 {
			page = v
		}
	}
	if ps := c.Query("page_size"); ps != "" {
		if v, err := parseInt(ps); err == nil && v > 0 && v <= 100 {
			pageSize = v
		}
	}

	skip := (page - 1) * pageSize
	opts := options.Find().SetSkip(int64(skip)).SetLimit(int64(pageSize)).SetSort(bson.D{{Key: "_id", Value: -1}})

	cursor, err := coll.Find(ctx, bson.M{}, opts)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	defer cursor.Close(ctx)

	var users []models.User
	if err = cursor.All(ctx, &users); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	total, _ := coll.CountDocuments(ctx, bson.M{})

	c.JSON(http.StatusOK, gin.H{
		"list":  users,
		"total": total,
		"page":  page,
		"page_size": pageSize,
	})
}

func GetUserByID(c *gin.Context) {
	id := c.Param("id")
	oid, err := bson.ObjectIDFromHex(id)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 ID"})
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	var user models.User
	err = config.GetDB(config.DBName).Collection("users").FindOne(ctx, bson.M{"_id": oid}).Decode(&user)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, user)
}

func CreateUser(c *gin.Context) {
	var input models.UserCreateInput
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	coll := config.GetDB(config.DBName).Collection("users")

	// 检查用户名是否已存在
	var exist models.User
	if err := coll.FindOne(ctx, bson.M{"username": input.Username}).Decode(&exist); err == nil {
		c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"})
		return
	}
	if err := coll.FindOne(ctx, bson.M{"email": input.Email}).Decode(&exist); err == nil {
		c.JSON(http.StatusConflict, gin.H{"error": "邮箱已存在"})
		return
	}

	if input.Role == "" {
		input.Role = "user"
	}
	roleID := input.RoleID
	if roleID == 0 {
		roleID = models.RoleIDUser
	}

	doc := bson.M{
		"username": input.Username,
		"email":    input.Email,
		"password": utils.HashPassword(input.Password),
		"role":     input.Role,
		"role_id":  roleID,
		"is_beta":  input.IsBeta,
	}
	if input.TrialStartDate != "" {
		doc["trial_start_date"] = input.TrialStartDate
	}
	if input.TrialEndDate != "" {
		doc["trial_end_date"] = input.TrialEndDate
	}
	if input.LLM != "" {
		doc["llm"] = input.LLM
	}

	res, err := coll.InsertOne(ctx, doc)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"id": res.InsertedID, "message": "创建成功"})
}

func UpdateUser(c *gin.Context) {
	id := c.Param("id")
	oid, err := bson.ObjectIDFromHex(id)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 ID"})
		return
	}

	var input models.UserUpdateInput
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	update := bson.M{}
	if input.Username != nil {
		update["username"] = *input.Username
	}
	if input.Email != nil {
		update["email"] = *input.Email
	}
	if input.Password != nil && *input.Password != "" {
		update["password"] = utils.HashPassword(*input.Password)
	}
	if input.Role != nil {
		update["role"] = *input.Role
	}
	if input.IsBeta != nil {
		update["is_beta"] = *input.IsBeta
	}
	if input.TrialStartDate != nil {
		update["trial_start_date"] = *input.TrialStartDate
	}
	if input.TrialEndDate != nil {
		update["trial_end_date"] = *input.TrialEndDate
	}
	if input.LLM != nil {
		update["llm"] = *input.LLM
	}
	if input.RoleID != nil {
		update["role_id"] = *input.RoleID
	}

	if len(update) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无有效更新字段"})
		return
	}

	res, err := config.GetDB(config.DBName).Collection("users").UpdateOne(ctx, bson.M{"_id": oid}, bson.M{"$set": update})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if res.MatchedCount == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "更新成功"})
}

func DeleteUser(c *gin.Context) {
	id := c.Param("id")
	oid, err := bson.ObjectIDFromHex(id)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 ID"})
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	res, err := config.GetDB(config.DBName).Collection("users").DeleteOne(ctx, bson.M{"_id": oid})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if res.DeletedCount == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
}
