package controller

import (
	"errors"
	"net/http"
	"slices"
	"strconv"
	"strings"
	"time"

	"opencatd-open/internal/consts"
	dto "opencatd-open/internal/dto/team"
	"opencatd-open/internal/model"
	service "opencatd-open/internal/service/team"
	"opencatd-open/internal/utils"

	"github.com/duke-git/lancet/v2/slice"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"gorm.io/gorm"
)

type Team struct {
	db           *gorm.DB
	userService  service.UserService
	tokenService service.TokenService
	keyService   service.ApiKeyService
	usageService service.UsageService
}

func NewTeam(userService service.UserService, tokenService service.TokenService, keyService service.ApiKeyService, usageService service.UsageService) *Team {
	return &Team{
		userService:  userService,
		tokenService: tokenService,
		keyService:   keyService,
		usageService: usageService,
	}
}

// initadmin
func (h *Team) InitAdmin(c *gin.Context) {
	admin, err := h.userService.GetUser(c, 1)

	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			user := &model.User{
				Name:     "root",
				Username: "root",
				Password: "openteam",
				Role:     utils.ToPtr(consts.RoleRoot),
				Tokens: []model.Token{
					{
						Name:           "default",
						Key:            "sk-team-" + strings.ReplaceAll(uuid.New().String(), "-", ""),
						UnlimitedQuota: utils.ToPtr(true),
					},
				},
			}
			if err := h.userService.CreateUser(c, user); err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
				return
			}
			var result = dto.UserInfo{
				ID:     user.ID,
				Name:   user.Username,
				Token:  user.Tokens[0].Key,
				Status: utils.ToPtr(user.Status == consts.StatusEnabled),
			}

			c.JSON(http.StatusOK, result)
			return
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}
	if admin != nil {
		c.JSON(http.StatusForbidden, gin.H{
			"error": "super user already exists, use cli to reset password",
		})
		return
	}
}

func (h *Team) Me(c *gin.Context) {
	token, exists := c.Get("token")
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "token not found"})
		return
	}
	userToken := token.(*model.Token)

	c.JSON(http.StatusOK, dto.UserInfo{
		ID:     userToken.UserID,
		Name:   userToken.User.Name,
		Token:  userToken.Key,
		Status: utils.ToPtr(userToken.User.Status == consts.StatusEnabled),
	})

}

// CreateUser 创建用户
func (h *Team) CreateUser(c *gin.Context) {
	var userReq dto.UserInfo
	if err := c.ShouldBindJSON(&userReq); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid input"})
		return
	}

	token, exists := c.Get("token")
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "Unauthorized"})
		return
	}
	userToken := token.(*model.Token)
	if *userToken.User.Role < consts.RoleAdmin { // 普通用户只能创建自己的token
		create := &model.Token{
			Name: userReq.Name,
			Key:  "sk-team-" + strings.ReplaceAll(uuid.New().String(), "-", ""),
		}
		if userReq.Token != "" {
			_key := strings.ReplaceAll(userReq.Token, "-", "")
			create.Key = "sk-team-" + strings.ReplaceAll(_key, " ", "")
		}
		if err := h.tokenService.Create(c.Request.Context(), create); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

	} else {
		user := &model.User{
			Name:     userReq.Name,
			Username: userReq.Name,
			Role:     utils.ToPtr(consts.RoleUser),
			Tokens: []model.Token{
				{
					Name: "default",
					Key:  "sk-team-" + strings.ReplaceAll(uuid.New().String(), "-", ""),
				},
			},
		}

		// 默认角色为普通用户
		if err := h.userService.CreateUser(c.Request.Context(), user); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "ok"})
}

// GetUser 获取用户信息
func (h *Team) GetUser(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	user, err := h.userService.GetUser(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, user)
}

// UpdateUser 更新用户信息
func (h *Team) UpdateUser(c *gin.Context) {
	var user model.User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid input"})
		return
	}
	token, exists := c.Get("token")
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "Unauthorized"})
		return
	}
	userToken := token.(*model.Token)

	operatorID := userToken.UserID // 假设从上下文中获取操作者ID
	if err := h.userService.UpdateUser(c.Request.Context(), &user, operatorID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "ok"})
}

// DeleteUser 删除用户
func (h *Team) DeleteUser(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	token, exists := c.Get("token")
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "Unauthorized"})
		return
	}
	userToken := token.(*model.Token)

	if *userToken.User.Role < consts.RoleAdmin { // 用户只能删除自己的token
		err := h.tokenService.Delete(c.Request.Context(), id)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	} else {
		if err := h.userService.DeleteUser(c, id, userToken.UserID); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "ok"})
}

func (h *Team) ListUsages(c *gin.Context) {
	fromStr := c.Query("from")
	toStr := c.Query("to")

	var from, to time.Time
	loc, _ := time.LoadLocation("Local")

	var listUsage []*dto.UsageInfo
	var err error

	if fromStr != "" && toStr != "" {

		from, err = time.Parse("2006-01-02", fromStr)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid from date"})
			return
		}
		to, err = time.Parse("2006-01-02", toStr)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid to date"})
			return
		}
	} else {
		year, month, _ := time.Now().In(loc).Date()
		from = time.Date(year, month, 1, 0, 0, 0, 0, loc)
		to = from.AddDate(0, 1, 0)
	}

	token, _ := c.Get("token")
	userToken := token.(*model.Token)
	if *userToken.User.Role < consts.RoleAdmin {
		listUsage, err = h.usageService.ListByDateRange(c.Request.Context(), from, to, map[string]interface{}{"user_id": userToken.UserID})
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	} else {
		listUsage, err = h.usageService.ListByDateRange(c.Request.Context(), from, to, nil)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

	c.JSON(http.StatusOK, listUsage)

}

// ListUsers 获取用户列表
func (h *Team) ListUsers(c *gin.Context) {
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "100"))
	offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
	active := c.DefaultQuery("active", "")

	if !slices.Contains([]string{"true", "false", ""}, active) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid active value"})
		return
	}

	token, exists := c.Get("token")
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "Unauthorized"})
		return
	}
	userToken := token.(*model.Token)
	if *userToken.User.Role < consts.RoleAdmin { // 用户只能获取自己的token
		tokens, _, err := h.tokenService.Lists(c, limit, offset)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		var userDTOs []dto.UserInfo
		for _, token := range tokens {
			userDTOs = append(userDTOs, dto.UserInfo{
				ID:     token.User.ID,
				Name:   token.User.Name,
				Token:  token.Key,
				Status: utils.ToPtr(token.User.Status == consts.StatusEnabled),
			})
		}
		c.JSON(http.StatusOK, userDTOs)
		return
	}

	users, err := h.userService.ListUsers(c, limit, offset, active)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	var userDTOs []dto.UserInfo
	for _, user := range users {
		useres := dto.UserInfo{
			ID:   user.ID,
			Name: user.Name,

			Status: utils.ToPtr(user.Status == consts.StatusEnabled),
		}
		if len(user.Tokens) > 0 {
			useres.Token = user.Tokens[0].Key
		}
		userDTOs = append(userDTOs, useres)
	}

	c.JSON(http.StatusOK, userDTOs)
}

func (h *Team) ResetUserToken(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}
	token, exists := c.Get("token")
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "Unauthorized"})
		return
	}
	userToken := token.(*model.Token)

	findtoken, err := h.tokenService.GetByUserID(c, id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	findtoken.Key = "sk-team-" + strings.ReplaceAll(uuid.New().String(), "-", "")

	if *userToken.User.Role < consts.RoleAdmin { // 非管理员只能修改自己的token
		if *userToken.User.Role <= *findtoken.User.Role || userToken.UserID != findtoken.UserID {
			c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
			return
		}
		err := h.tokenService.UpdateWithCondition(c, findtoken, map[string]interface{}{"user_id": userToken.UserID}, nil)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	} else {
		if err := h.tokenService.Update(c, findtoken); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

	c.JSON(http.StatusOK, dto.UserInfo{
		ID:    findtoken.User.ID,
		Name:  findtoken.User.Name,
		Token: findtoken.Key,
	})
}

func (h *Team) CreateKey(c *gin.Context) {
	token, exists := c.Get("token")
	if !exists {
		c.JSON(http.StatusNotFound, gin.H{"error": "token not found"})
		return
	}
	userToken := token.(*model.Token)
	if *userToken.User.Role < consts.RoleAdmin {
		c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
		return
	}

	var key dto.ApiKeyInfo
	if err := c.ShouldBindJSON(&key); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	err := h.keyService.Create(&model.ApiKey{
		Name:     utils.ToPtr(key.Name),
		ApiType:  utils.ToPtr(key.ApiType),
		ApiKey:   utils.ToPtr(key.Key),
		Endpoint: utils.ToPtr(key.Endpoint),
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, key)
}

func (h *Team) ListKeys(c *gin.Context) {
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
	offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
	active := c.Query("active")
	if !slice.Contain([]string{"true", "false", ""}, active) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid active value"})
		return
	}

	keys, err := h.keyService.List(limit, offset, active)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	var keysDTO []dto.ApiKeyInfo
	for _, key := range keys {
		keylength := len(*key.ApiKey) / 3
		if keylength < 1 {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid key length"})
			return
		}
		keysDTO = append(keysDTO, dto.ApiKeyInfo{
			ID:       int(key.ID),
			Name:     *key.Name,
			ApiType:  *key.ApiType,
			Endpoint: *key.Endpoint,
			Key:      *key.ApiKey,
		})
	}
	c.JSON(http.StatusOK, keysDTO)
}

func (h *Team) UpdateKey(c *gin.Context) {
	// 1. 获取并验证ID
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid key id"})
		return
	}

	// 2. 解析请求体
	var updateKey dto.ApiKeyInfo // 更明确的命名
	if err := c.ShouldBindJSON(&updateKey); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 3. 获取现有记录
	existingKey, err := h.keyService.GetByID(id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 4. 使用 UpdateFields 方法统一处理字段更新
	updatedKey := updateKey.UpdateFields(existingKey)

	// 5. 保存更新
	if err := h.keyService.Update(updatedKey); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, updatedKey)
}

func (h *Team) DeleteKey(c *gin.Context) {
	// 1. 获取并验证ID
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid key id"})
		return
	}

	// 2. 删除记录
	if err := h.keyService.Delete(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "ok"})
}

// ChangePassword 修改密码
func (h *Team) ChangePassword(c *gin.Context) {
	userID := c.GetInt64("userID") // 假设从上下文中获取用户ID

	var req struct {
		OldPassword string `json:"oldPassword"`
		NewPassword string `json:"newPassword"`
	}

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

	if err := h.userService.ChangePassword(c.Request.Context(), userID, req.OldPassword, req.NewPassword); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "ok"})
}

// ResetPassword 重置密码
func (h *Team) ResetPassword(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	operatorID := int64(c.GetInt("userID")) // 假设从上下文中获取操作者ID
	if err := h.userService.ResetPassword(c.Request.Context(), id, operatorID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "password reset successfully"})
}

// EnableUser 启用用户
func (h *Team) EnableUser(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	operatorID := int64(c.GetInt("userID")) // 假设从上下文中获取操作者ID

	if err := h.userService.BatchEnableUsers(c, []int64{id}, operatorID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "user enabled successfully"})
}

// DisableUser 禁用用户
func (h *Team) DisableUser(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	operatorID := int64(c.GetInt("userID")) // 假设从上下文中获取操作者ID
	if err := h.userService.BatchDisableUsers(c.Request.Context(), []int64{id}, operatorID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "user disabled successfully"})
}
