package application

import (
	"errors"
	"fmt"
)

var (
	// ErrServiceAlreadyRegistered appears when trying to register a service with already taken name.
	ErrServiceAlreadyRegistered = errors.New("service already registered")
	// ErrServiceNotRegistered appears when trying to get a registered service with unknown name.
	ErrServiceNotRegistered = errors.New("unknown service")
)

// Service это интерфейс, которому должны соответствовать все сервисы, используемые в приложении.
type Service interface {
	ConnectDependencies() error
	GetName() string
	Initialize() error
	LaunchStartupTasks() error
	Shutdown() error
}

// GetService возвращает сервис по имени, или же ошибку, если сервис не был зарегистрирован ранее.
func (a *Application) GetService(name string) (Service, error) {
	a.servicesMutex.RLock()
	service, found := a.services[name]
	a.servicesMutex.RUnlock()

	if !found {
		return nil, fmt.Errorf("%w: get service '%s': %w", ErrApplication, name, ErrServiceNotRegistered)
	}

	return service, nil
}

// RegisterService регистрирует сервис, или возвращает ошибку, если сервис с таким именем уже был
// зарегистрирован ранее.
func (a *Application) RegisterService(service Service) error {
	_, found := a.services[service.GetName()]
	if found {
		return fmt.Errorf("%w: register service '%s': %w", ErrApplication, service.GetName(), ErrServiceAlreadyRegistered)
	}

	if err := service.Initialize(); err != nil {
		return fmt.Errorf("%w: initializing service '%s': %w", ErrApplication, service.GetName(), err)
	}

	a.servicesMutex.Lock()
	a.services[service.GetName()] = service
	a.servicesMutex.Unlock()

	return nil
}
