package system

import (
	"context"
	"kra/internal/biz/system"

	"kra/internal/service/dto"
)

type UserService struct {
	uc       *system.UserUsecase
	settings *SecurityService
}

func NewUserService(uc *system.UserUsecase, settings *SecurityService) *UserService {
	return &UserService{uc: uc, settings: settings}
}

func (s *UserService) ListUsersRequest(ctx context.Context, value *dto.UserListRequest) ([]*dto.UserResponse, int64, error) {
	users, total, err := s.uc.ListUsers(ctx, value.Page, value.PageSize, &system.UserListFilter{Username: value.Username, NickName: value.NickName, Phone: value.Phone, Email: value.Email, OrderKey: value.OrderKey, Desc: value.Desc})
	if err != nil {
		return nil, 0, err
	}
	result := make([]*dto.UserResponse, 0, len(users))
	for _, user := range users {
		result = append(result, convertUser(user))
	}
	return result, total, nil
}

func (s *UserService) CreateUserRequest(ctx context.Context, value *dto.UserRequest) (*dto.UserResponse, error) {
	security, err := s.settings.CurrentSecurity(ctx)
	if err != nil {
		return nil, err
	}
	if err := s.settings.ValidatePasswordWithConfig(security, value.Password); err != nil {
		return nil, err
	}
	mustChange := security != nil && security.ForceNewUserChangePassword
	user, err := s.uc.CreateUser(ctx, &system.User{Username: value.Username, Password: value.Password, NickName: value.NickName, HeaderImg: value.HeaderImg, AuthorityID: value.AuthorityID, Phone: value.Phone, Email: value.Email, Enable: value.Enable, MustChangePassword: mustChange}, value.AuthorityIDs)
	if err != nil {
		return nil, err
	}
	return convertUser(user), nil
}

func (s *UserService) UpdateUserRequest(ctx context.Context, value *dto.UserRequest) error {
	// The compatible ChangeUserInfo payload uses authorityIds for role assignment; the
	// standalone authorityId field is not applied by setUserInfo.
	return s.uc.UpdateUser(ctx, &system.User{ID: value.ID, NickName: value.NickName, HeaderImg: value.HeaderImg, Phone: value.Phone, Email: value.Email, Enable: value.Enable}, value.AuthorityIDs)
}

func (s *UserService) UpdateSelfUserRequest(ctx context.Context, id uint, value *dto.SelfUserRequest) error {
	return s.uc.UpdateSelfUser(ctx, &system.User{ID: id, NickName: value.NickName, HeaderImg: value.HeaderImg, Phone: value.Phone, Email: value.Email, Enable: value.Enable})
}

func (s *UserService) UserByUUID(ctx context.Context, uuid string) (*dto.UserResponse, error) {
	value, err := s.uc.UserByUUID(ctx, uuid)
	if err != nil {
		return nil, err
	}
	return convertUser(value), nil
}

func (s *UserService) Menus(ctx context.Context, authorityID uint) ([]*dto.DynamicMenuResponse, error) {
	menus, err := s.uc.Menus(ctx, authorityID)
	if err != nil {
		return nil, err
	}
	return dynamicMenuResponses(menus), nil
}

func (s *UserService) Authorities(ctx context.Context) ([]*dto.AuthorityResponse, error) {
	values, err := s.uc.Authorities(ctx)
	if err != nil {
		return nil, err
	}
	result := make([]*dto.AuthorityResponse, 0, len(values))
	for _, value := range values {
		result = append(result, convertAuthority(*value))
	}
	return result, nil
}

func (s *UserService) DeleteUser(ctx context.Context, id uint) error {
	return s.uc.DeleteUser(ctx, id)
}
func (s *UserService) ResetPassword(ctx context.Context, id uint, password string) error {
	if err := s.settings.ValidatePassword(ctx, password); err != nil {
		return err
	}
	return s.uc.ResetPassword(ctx, id, password)
}
func (s *UserService) ChangePassword(ctx context.Context, id uint, oldPassword, newPassword string) error {
	if err := s.settings.ValidatePassword(ctx, newPassword); err != nil {
		return err
	}
	return s.uc.ChangePassword(ctx, id, oldPassword, newPassword)
}

func (s *UserService) SetUserAuthorities(ctx context.Context, id uint, authorityIDs []uint) error {
	return s.uc.SetUserAuthorities(ctx, id, authorityIDs)
}
func (s *UserService) SetUserSetting(ctx context.Context, id uint, setting map[string]any) error {
	return s.uc.SetUserSetting(ctx, id, setting)
}
