package auth

import (
	"net/http"
	"time"

	"github.com/veypi/vbase/internal/cache"
	"github.com/veypi/vbase/internal/config"
	"github.com/veypi/vbase/internal/model"
	"github.com/veypi/vbase/internal/pkg/crypto"
	"github.com/veypi/vbase/internal/pkg/jwt"
	"github.com/veypi/vigo"
)

// LoginRequest 登录请求
type LoginRequest struct {
	Username     string `json:"username" src:"json" desc:"用户名/邮箱/手机号"`
	Password     string `json:"password" src:"json" desc:"密码"`
	CaptchaID    string `json:"captcha_id,omitempty" src:"json" desc:"验证码ID"`
	CaptchaCode  string `json:"captcha_code,omitempty" src:"json" desc:"验证码"`
	Remember     bool   `json:"remember,omitempty" src:"json" desc:"记住登录"`
}

// RegisterRequest 注册请求
type RegisterRequest struct {
	Username string `json:"username" src:"json" desc:"用户名"`
	Password string `json:"password" src:"json" desc:"密码"`
	Email    string `json:"email,omitempty" src:"json" desc:"邮箱"`
	Phone    string `json:"phone,omitempty" src:"json" desc:"手机号"`
	Nickname string `json:"nickname,omitempty" src:"json" desc:"昵称"`
}

// AuthResponse 认证响应
type AuthResponse struct {
	AccessToken  string     `json:"access_token"`
	RefreshToken string     `json:"refresh_token"`
	TokenType    string     `json:"token_type"`
	ExpiresIn    int        `json:"expires_in"`
	User         *UserInfo  `json:"user"`
}

// UserInfo 用户信息
type UserInfo struct {
	ID       string `json:"id"`
	Username string `json:"username"`
	Nickname string `json:"nickname"`
	Email    string `json:"email"`
	Avatar   string `json:"avatar"`
}

// Login 用户登录
func Login(x *vigo.X, req *LoginRequest) (*AuthResponse, error) {
	// 查找用户
	var user model.User
	query := model.DB.Where("username = ? OR email = ? OR phone = ?", req.Username, req.Username, req.Username)
	if err := query.First(&user).Error; err != nil {
		return nil, vigo.ErrNotAuthorized.WithString("invalid username or password")
	}

	// 检查用户状态
	if user.Status != model.UserStatusActive {
		return nil, vigo.ErrForbidden.WithString("user is disabled")
	}

	// 验证密码
	if !crypto.VerifyPassword(req.Password, user.Password) {
		return nil, vigo.ErrNotAuthorized.WithString("invalid username or password")
	}

	// 获取用户的组织信息
	orgs, err := getUserOrgs(user.ID)
	if err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	// 生成token
	orgClaims := make([]jwt.OrgClaim, 0, len(orgs))
	for _, org := range orgs {
		orgClaims = append(orgClaims, jwt.OrgClaim{
			OrgID:  org.OrgID,
			Code:   org.Code,
			Name:   org.Name,
			Roles:  org.Roles,
			Status: org.Status,
		})
	}

	tokenPair, err := jwt.GenerateTokenPair(
		user.ID,
		user.Username,
		user.Nickname,
		user.Avatar,
		user.Email,
		orgClaims,
	)
	if err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	// 保存session
	session := &model.Session{
		UserID:     user.ID,
		TokenID:    getJTI(tokenPair.AccessToken),
		Type:       "access",
		DeviceInfo: x.Request.UserAgent(),
		IP:         x.GetRemoteIP(),
		ExpiresAt:  time.Now().Add(config.C.JWT.AccessExpiry),
	}
	model.DB.Create(session)

	// 更新最后登录时间
	now := time.Now()
	model.DB.Model(&user).Update("last_login_at", now)

	return &AuthResponse{
		AccessToken:  tokenPair.AccessToken,
		RefreshToken: tokenPair.RefreshToken,
		TokenType:    tokenPair.TokenType,
		ExpiresIn:    tokenPair.ExpiresIn,
		User: &UserInfo{
			ID:       user.ID,
			Username: user.Username,
			Nickname: user.Nickname,
			Email:    user.Email,
			Avatar:   user.Avatar,
		},
	}, nil
}

// Register 用户注册
func Register(x *vigo.X, req *RegisterRequest) (*AuthResponse, error) {
	// 检查用户名是否已存在
	var count int64
	model.DB.Model(&model.User{}).Where("username = ?", req.Username).Count(&count)
	if count > 0 {
		return nil, vigo.ErrArgInvalid.WithString("username already exists")
	}

	// 检查邮箱是否已存在
	if req.Email != "" {
		model.DB.Model(&model.User{}).Where("email = ?", req.Email).Count(&count)
		if count > 0 {
			return nil, vigo.ErrArgInvalid.WithString("email already exists")
		}
	}

	// 哈希密码
	hashedPassword, err := crypto.HashPassword(req.Password, config.C.Security.BcryptCost)
	if err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	// 创建用户
	user := &model.User{
		Username: req.Username,
		Password: hashedPassword,
		Email:    req.Email,
		Phone:    req.Phone,
		Nickname: req.Nickname,
		Status:   model.UserStatusActive,
	}

	if user.Nickname == "" {
		user.Nickname = user.Username
	}

	if err := model.DB.Create(user).Error; err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	// 生成token
	tokenPair, err := jwt.GenerateTokenPair(
		user.ID,
		user.Username,
		user.Nickname,
		user.Avatar,
		user.Email,
		nil, // 新用户无组织
	)
	if err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	// 保存session
	session := &model.Session{
		UserID:     user.ID,
		TokenID:    getJTI(tokenPair.AccessToken),
		Type:       "access",
		DeviceInfo: x.Request.UserAgent(),
		IP:         x.GetRemoteIP(),
		ExpiresAt:  time.Now().Add(config.C.JWT.AccessExpiry),
	}
	model.DB.Create(session)

	return &AuthResponse{
		AccessToken:  tokenPair.AccessToken,
		RefreshToken: tokenPair.RefreshToken,
		TokenType:    tokenPair.TokenType,
		ExpiresIn:    tokenPair.ExpiresIn,
		User: &UserInfo{
			ID:       user.ID,
			Username: user.Username,
			Nickname: user.Nickname,
			Email:    user.Email,
			Avatar:   user.Avatar,
		},
	}, nil
}

// RefreshRequest 刷新请求
type RefreshRequest struct {
	RefreshToken string `json:"refresh_token" src:"json" desc:"刷新令牌"`
}

// Refresh 刷新Token
func Refresh(x *vigo.X, req *RefreshRequest) (*AuthResponse, error) {
	// 解析refresh token
	claims, err := jwt.ParseToken(req.RefreshToken)
	if err != nil {
		if err == jwt.ErrExpiredToken {
			return nil, vigo.ErrNotAuthorized.WithString("refresh token expired")
		}
		return nil, vigo.ErrNotAuthorized.WithString("invalid refresh token")
	}

	if !jwt.IsRefreshToken(claims) {
		return nil, vigo.ErrNotAuthorized.WithString("invalid token type")
	}

	// 查找用户
	var user model.User
	if err := model.DB.First(&user, "id = ?", claims.UserID).Error; err != nil {
		return nil, vigo.ErrNotAuthorized.WithString("user not found")
	}

	if user.Status != model.UserStatusActive {
		return nil, vigo.ErrForbidden.WithString("user is disabled")
	}

	// 获取用户的组织信息
	orgs, err := getUserOrgs(user.ID)
	if err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	orgClaims := make([]jwt.OrgClaim, 0, len(orgs))
	for _, org := range orgs {
		orgClaims = append(orgClaims, jwt.OrgClaim{
			OrgID:  org.OrgID,
			Code:   org.Code,
			Name:   org.Name,
			Roles:  org.Roles,
			Status: org.Status,
		})
	}

	// 生成新token
	tokenPair, err := jwt.GenerateTokenPair(
		user.ID,
		user.Username,
		user.Nickname,
		user.Avatar,
		user.Email,
		orgClaims,
	)
	if err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	// 保存新session
	session := &model.Session{
		UserID:     user.ID,
		TokenID:    getJTI(tokenPair.AccessToken),
		Type:       "access",
		DeviceInfo: x.Request.UserAgent(),
		IP:         x.GetRemoteIP(),
		ExpiresAt:  time.Now().Add(config.C.JWT.AccessExpiry),
	}
	model.DB.Create(session)

	return &AuthResponse{
		AccessToken:  tokenPair.AccessToken,
		RefreshToken: tokenPair.RefreshToken,
		TokenType:    tokenPair.TokenType,
		ExpiresIn:    tokenPair.ExpiresIn,
		User: &UserInfo{
			ID:       user.ID,
			Username: user.Username,
			Nickname: user.Nickname,
			Email:    user.Email,
			Avatar:   user.Avatar,
		},
	}, nil
}

// Logout 用户登出
func Logout(x *vigo.X) error {
	tokenString := extractTokenFromRequest(x.Request)
	if tokenString == "" {
		return nil
	}

	jti, err := jwt.GetJTI(tokenString)
	if err != nil {
		return nil
	}

	// 加入黑名单
	expiration, _ := jwt.GetExpiration(tokenString)
	if cache.IsEnabled() {
		ttl := time.Until(expiration)
		if ttl > 0 {
			cache.BlacklistToken(jti, ttl)
		}
	}

	// 标记session为撤销
	model.DB.Model(&model.Session{}).Where("token_id = ?", jti).Updates(map[string]interface{}{
		"revoked":    true,
		"revoked_at": time.Now(),
	})

	return nil
}

// Me 获取当前用户信息
func Me(x *vigo.X) (*UserInfo, error) {
	userID := getCurrentUserID(x)
	if userID == "" {
		return nil, vigo.ErrNotAuthorized
	}

	var user model.User
	if err := model.DB.First(&user, "id = ?", userID).Error; err != nil {
		return nil, vigo.ErrNotFound
	}

	return &UserInfo{
		ID:       user.ID,
		Username: user.Username,
		Nickname: user.Nickname,
		Email:    user.Email,
		Avatar:   user.Avatar,
	}, nil
}

// UpdateMeRequest 更新自己请求
type UpdateMeRequest struct {
	Nickname *string `json:"nickname,omitempty" src:"json" desc:"昵称"`
	Avatar   *string `json:"avatar,omitempty" src:"json" desc:"头像"`
	Email    *string `json:"email,omitempty" src:"json" desc:"邮箱"`
}

// UpdateMe 更新当前用户信息
func UpdateMe(x *vigo.X, req *UpdateMeRequest) (*UserInfo, error) {
	userID := getCurrentUserID(x)
	if userID == "" {
		return nil, vigo.ErrNotAuthorized
	}

	updates := make(map[string]interface{})
	if req.Nickname != nil {
		updates["nickname"] = *req.Nickname
	}
	if req.Avatar != nil {
		updates["avatar"] = *req.Avatar
	}
	if req.Email != nil {
		// 检查邮箱是否被其他用户使用
		var count int64
		model.DB.Model(&model.User{}).Where("email = ? AND id != ?", *req.Email, userID).Count(&count)
		if count > 0 {
			return nil, vigo.ErrArgInvalid.WithString("email already exists")
		}
		updates["email"] = *req.Email
	}

	if err := model.DB.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	return Me(x)
}

// ChangePasswordRequest 修改密码请求
type ChangePasswordRequest struct {
	OldPassword string `json:"old_password" src:"json" desc:"旧密码"`
	NewPassword string `json:"new_password" src:"json" desc:"新密码"`
}

// ChangePassword 修改密码
func ChangePassword(x *vigo.X, req *ChangePasswordRequest) error {
	userID := getCurrentUserID(x)
	if userID == "" {
		return vigo.ErrNotAuthorized
	}

	var user model.User
	if err := model.DB.First(&user, "id = ?", userID).Error; err != nil {
		return vigo.ErrNotFound
	}

	// 验证旧密码
	if !crypto.VerifyPassword(req.OldPassword, user.Password) {
		return vigo.ErrArgInvalid.WithString("old password is incorrect")
	}

	// 哈希新密码
	hashedPassword, err := crypto.HashPassword(req.NewPassword, config.C.Security.BcryptCost)
	if err != nil {
		return vigo.ErrInternalServer.WithError(err)
	}

	// 更新密码
	if err := model.DB.Model(&user).Update("password", hashedPassword).Error; err != nil {
		return vigo.ErrInternalServer.WithError(err)
	}

	return nil
}

// helper functions

func getCurrentUserID(x *vigo.X) string {
	if uid, ok := x.Get("current_user").(string); ok {
		return uid
	}
	return ""
}

func extractToken(r *vigo.X) string {
	// 从Header获取
	auth := r.Request.Header.Get("Authorization")
	if auth != "" {
		parts := make([]string, 0)
		for _, p := range []string{auth} {
			parts = append(parts, p)
		}
		// Simple check
		if len(auth) > 7 && auth[:7] == "Bearer " {
			return auth[7:]
		}
	}

	// 从Query获取
	return r.Request.URL.Query().Get("access_token")
}

func extractTokenFromRequest(r *http.Request) string {
	// 从Header获取
	auth := r.Header.Get("Authorization")
	if auth != "" {
		if len(auth) > 7 && auth[:7] == "Bearer " {
			return auth[7:]
		}
	}

	// 从Query获取
	return r.URL.Query().Get("access_token")
}

func getJTI(token string) string {
	jti, _ := jwt.GetJTI(token)
	return jti
}

type userOrgInfo struct {
	OrgID  string
	Code   string
	Name   string
	Roles  []string
	Status int
}

func getUserOrgs(userID string) ([]userOrgInfo, error) {
	var members []model.OrgMember
	if err := model.DB.Where("user_id = ? AND status = ?", userID, model.MemberStatusActive).Find(&members).Error; err != nil {
		return nil, err
	}

	if len(members) == 0 {
		return []userOrgInfo{}, nil
	}

	result := make([]userOrgInfo, 0, len(members))
	for _, m := range members {
		var org model.Org
		if err := model.DB.First(&org, "id = ?", m.OrgID).Error; err != nil {
			continue
		}

		// 解析角色ID
		roles := parseRoles(m.RoleIDs)

		result = append(result, userOrgInfo{
			OrgID:  m.OrgID,
			Code:   org.Code,
			Name:   org.Name,
			Roles:  roles,
			Status: m.Status,
		})
	}

	return result, nil
}

func parseRoles(roleIDs string) []string {
	if roleIDs == "" {
		return []string{}
	}
	// 简单解析，实际可能需要更复杂的逻辑
	return []string{}
}
