package system

import (
	"context"
	"encoding/json"
	"errors"
	"time"

	"github.com/google/uuid"
	"golang.org/x/crypto/bcrypt"
)

var (
	ErrUserNotFound       = errors.New("用户不存在")
	ErrUserAlreadyExists  = errors.New("用户名已注册")
	ErrPasswordWrong      = errors.New("密码错误")
	ErrOldPasswordWrong   = errors.New("原密码错误")
	ErrUserNoAuthority    = errors.New("该用户无此角色")
	ErrDefaultRouterEmpty = errors.New("找不到默认路由,无法切换本角色")
)

// User 用户实体
type User struct {
	ID            uint
	UUID          uuid.UUID
	Username      string
	Password      string
	NickName      string
	SideMode      string
	HeaderImg     string
	BaseColor     string
	AuthorityId   uint
	Phone         string
	Email         string
	Enable        int
	OriginSetting json.RawMessage
	Authority     *Authority
	Authorities   []*Authority
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

// Authority 角色实体
type Authority struct {
	AuthorityId   uint
	AuthorityName string
	ParentId      *uint
	DefaultRouter string
}

// UserRepo 用户仓储接口
type UserRepo interface {
	Create(ctx context.Context, user *User) error
	Update(ctx context.Context, user *User) error
	UpdateSelf(ctx context.Context, user *User) error
	UpdateSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error
	Delete(ctx context.Context, id uint) error
	FindByID(ctx context.Context, id uint) (*User, error)
	FindByIDWithAuthorities(ctx context.Context, id uint) (*User, error)
	FindByUUID(ctx context.Context, uuid string) (*User, error)
	FindByUUIDWithAuthorities(ctx context.Context, uuid string) (*User, error)
	FindByUsername(ctx context.Context, username string) (*User, error)
	FindByUsernameWithAuthorities(ctx context.Context, username string) (*User, error)
	List(ctx context.Context, page, pageSize int, filters map[string]string) ([]*User, int64, error)
	UpdatePassword(ctx context.Context, id uint, password string) error
	UpdateAuthorityID(ctx context.Context, id uint, authorityId uint) error
	SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error
	CheckUserHasAuthority(ctx context.Context, userId, authorityId uint) (bool, error)
	GetAuthorityMenuRouters(ctx context.Context, authorityId uint) ([]string, error)
	GetAuthorityDefaultRouter(ctx context.Context, authorityId uint) (string, error)
}

// UserUsecase 用户用例
type UserUsecase struct {
	repo UserRepo
}

// NewUserUsecase 创建用户用例
func NewUserUsecase(repo UserRepo) *UserUsecase {
	return &UserUsecase{repo: repo}
}

// Register 用户注册
func (uc *UserUsecase) Register(ctx context.Context, user *User) (*User, error) {
	// 检查用户名是否已存在
	existing, _ := uc.repo.FindByUsername(ctx, user.Username)
	if existing != nil {
		return nil, ErrUserAlreadyExists
	}

	// 密码加密
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}
	user.Password = string(hashedPassword)
	user.UUID = uuid.New()

	if err := uc.repo.Create(ctx, user); err != nil {
		return nil, err
	}
	return user, nil
}

// Login 用户登录（预加载Authorities）
func (uc *UserUsecase) Login(ctx context.Context, username, password string) (*User, error) {
	user, err := uc.repo.FindByUsernameWithAuthorities(ctx, username)
	if err != nil {
		return nil, ErrUserNotFound
	}

	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
		return nil, ErrPasswordWrong
	}

	return user, nil
}

// ChangePassword 修改密码
func (uc *UserUsecase) ChangePassword(ctx context.Context, id uint, oldPassword, newPassword string) error {
	user, err := uc.repo.FindByID(ctx, id)
	if err != nil {
		return ErrUserNotFound
	}

	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)); err != nil {
		return ErrOldPasswordWrong
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		return err
	}

	return uc.repo.UpdatePassword(ctx, id, string(hashedPassword))
}

// ResetPassword 重置密码
func (uc *UserUsecase) ResetPassword(ctx context.Context, id uint, newPassword string) error {
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	return uc.repo.UpdatePassword(ctx, id, string(hashedPassword))
}

// GetUserInfo 获取用户信息（预加载Authorities）
func (uc *UserUsecase) GetUserInfo(ctx context.Context, uuid string) (*User, error) {
	return uc.repo.FindByUUIDWithAuthorities(ctx, uuid)
}

// GetUserByID 通过ID获取用户
func (uc *UserUsecase) GetUserByID(ctx context.Context, id uint) (*User, error) {
	return uc.repo.FindByID(ctx, id)
}

// FindUserById 通过ID获取用户（GVA兼容）
func (uc *UserUsecase) FindUserById(ctx context.Context, id uint) (*User, error) {
	return uc.repo.FindByID(ctx, id)
}

// FindUserByUuid 通过UUID获取用户（GVA兼容）
func (uc *UserUsecase) FindUserByUuid(ctx context.Context, uuid string) (*User, error) {
	return uc.repo.FindByUUID(ctx, uuid)
}

// GetUserList 获取用户列表
func (uc *UserUsecase) GetUserList(ctx context.Context, page, pageSize int, filters map[string]string) ([]*User, int64, error) {
	return uc.repo.List(ctx, page, pageSize, filters)
}

// SetUserInfo 设置用户信息（管理员用）
func (uc *UserUsecase) SetUserInfo(ctx context.Context, user *User) error {
	return uc.repo.Update(ctx, user)
}

// SetSelfInfo 设置自己的信息（用户用）
func (uc *UserUsecase) SetSelfInfo(ctx context.Context, user *User) error {
	return uc.repo.UpdateSelf(ctx, user)
}

// SetSelfSetting 设置自己的配置
func (uc *UserUsecase) SetSelfSetting(ctx context.Context, id uint, setting json.RawMessage) error {
	return uc.repo.UpdateSelfSetting(ctx, id, setting)
}

// DeleteUser 删除用户
func (uc *UserUsecase) DeleteUser(ctx context.Context, id uint) error {
	return uc.repo.Delete(ctx, id)
}

// SetUserAuthority 设置用户角色（切换角色）
func (uc *UserUsecase) SetUserAuthority(ctx context.Context, id uint, authorityId uint) error {
	// 检查用户是否拥有该角色
	hasAuthority, err := uc.repo.CheckUserHasAuthority(ctx, id, authorityId)
	if err != nil {
		return err
	}
	if !hasAuthority {
		return ErrUserNoAuthority
	}

	// 获取角色的默认路由
	defaultRouter, err := uc.repo.GetAuthorityDefaultRouter(ctx, authorityId)
	if err != nil {
		return err
	}

	// 获取角色的菜单路由列表
	menuRouters, err := uc.repo.GetAuthorityMenuRouters(ctx, authorityId)
	if err != nil {
		return err
	}

	// 检查默认路由是否在菜单中
	hasMenu := false
	for _, router := range menuRouters {
		if router == defaultRouter {
			hasMenu = true
			break
		}
	}
	if !hasMenu {
		return ErrDefaultRouterEmpty
	}

	return uc.repo.UpdateAuthorityID(ctx, id, authorityId)
}

// SetUserAuthorities 设置用户多角色
func (uc *UserUsecase) SetUserAuthorities(ctx context.Context, adminAuthorityID, userId uint, authorityIds []uint) error {
	return uc.repo.SetUserAuthorities(ctx, adminAuthorityID, userId, authorityIds)
}
