package service

import (
	"context"
	"fmt"

	"git.kirlllll.ru/volontery/backend/internal/database"
	"git.kirlllll.ru/volontery/backend/internal/repository"
)

// UserService предоставляет методы для работы с пользователями
type UserService struct {
	userRepo *repository.UserRepository
	rbacRepo *repository.RBACRepository
}

// NewUserService создает новый UserService
func NewUserService(userRepo *repository.UserRepository, rbacRepo *repository.RBACRepository) *UserService {
	return &UserService{
		userRepo: userRepo,
		rbacRepo: rbacRepo,
	}
}

// GetUserProfile получает профиль пользователя
func (s *UserService) GetUserProfile(ctx context.Context, userID int64) (*database.GetUserProfileRow, error) {
	return s.userRepo.GetProfile(ctx, userID)
}

// UpdateProfileInput - входные данные для обновления профиля
type UpdateProfileInput struct {
	FirstName string `json:"first_name,omitempty"`
	LastName  string `json:"last_name,omitempty"`
	Phone     string `json:"phone,omitempty"`
	Bio       string `json:"bio,omitempty"`
	Address   string `json:"address,omitempty"`
	City      string `json:"city,omitempty"`
}

// UpdateUserProfile обновляет профиль пользователя
func (s *UserService) UpdateUserProfile(ctx context.Context, userID int64, input UpdateProfileInput) error {
	return s.userRepo.UpdateProfile(ctx, database.UpdateUserProfileParams{
		UserID:    userID,
		FirstName: stringToPgText(input.FirstName),
		LastName:  stringToPgText(input.LastName),
		Phone:     stringToPgText(input.Phone),
		Address:   stringToPgText(input.Address),
		City:      stringToPgText(input.City),
	})
}

// UpdateUserLocation обновляет местоположение пользователя
func (s *UserService) UpdateUserLocation(ctx context.Context, userID int64, lat, lon float64) error {
	if lat == 0 || lon == 0 {
		return fmt.Errorf("invalid coordinates")
	}

	return s.userRepo.UpdateLocation(ctx, database.UpdateUserLocationParams{
		ID:            userID,
		StMakepoint:   lon,
		StMakepoint_2: lat,
	})
}

// VerifyEmail подтверждает email пользователя
func (s *UserService) VerifyEmail(ctx context.Context, userID int64) error {
	return s.userRepo.VerifyEmail(ctx, userID)
}

// GetUserRoles получает роли пользователя
func (s *UserService) GetUserRoles(ctx context.Context, userID int64) ([]database.Role, error) {
	return s.rbacRepo.GetUserRoles(ctx, userID)
}

// GetUserPermissions получает разрешения пользователя
func (s *UserService) GetUserPermissions(ctx context.Context, userID int64) ([]database.GetUserPermissionsRow, error) {
	return s.rbacRepo.GetUserPermissions(ctx, userID)
}

// HasPermission проверяет наличие разрешения у пользователя
func (s *UserService) HasPermission(ctx context.Context, userID int64, permissionName string) (bool, error) {
	return s.rbacRepo.UserHasPermission(ctx, database.UserHasPermissionParams{
		ID:   userID,
		Name: permissionName,
	})
}

// AssignRole назначает роль пользователю
func (s *UserService) AssignRole(ctx context.Context, userID, roleID, assignedBy int64) error {
	_, err := s.rbacRepo.AssignRoleToUser(ctx, database.AssignRoleToUserParams{
		UserID:     userID,
		RoleID:     roleID,
		AssignedBy: int64ToPgInt8(assignedBy),
	})
	return err
}
