package services import ( "encoding/json" "errors" "github.com/google/uuid" "git.mchus.pro/mchus/quoteforge/internal/models" "git.mchus.pro/mchus/quoteforge/internal/repository" ) var ( ErrConfigNotFound = errors.New("configuration not found") ErrConfigForbidden = errors.New("access to configuration forbidden") ) type ConfigurationService struct { configRepo *repository.ConfigurationRepository componentRepo *repository.ComponentRepository quoteService *QuoteService } func NewConfigurationService( configRepo *repository.ConfigurationRepository, componentRepo *repository.ComponentRepository, quoteService *QuoteService, ) *ConfigurationService { return &ConfigurationService{ configRepo: configRepo, componentRepo: componentRepo, quoteService: quoteService, } } type CreateConfigRequest struct { Name string `json:"name"` Items models.ConfigItems `json:"items"` Notes string `json:"notes"` IsTemplate bool `json:"is_template"` } func (s *ConfigurationService) Create(userID uint, req *CreateConfigRequest) (*models.Configuration, error) { total := req.Items.Total() config := &models.Configuration{ UUID: uuid.New().String(), UserID: userID, Name: req.Name, Items: req.Items, TotalPrice: &total, Notes: req.Notes, IsTemplate: req.IsTemplate, } if err := s.configRepo.Create(config); err != nil { return nil, err } // Record usage stats _ = s.quoteService.RecordUsage(req.Items) return config, nil } func (s *ConfigurationService) GetByUUID(uuid string, userID uint) (*models.Configuration, error) { config, err := s.configRepo.GetByUUID(uuid) if err != nil { return nil, ErrConfigNotFound } // Allow access if user owns config or it's a template if config.UserID != userID && !config.IsTemplate { return nil, ErrConfigForbidden } return config, nil } func (s *ConfigurationService) Update(uuid string, userID uint, req *CreateConfigRequest) (*models.Configuration, error) { config, err := s.configRepo.GetByUUID(uuid) if err != nil { return nil, ErrConfigNotFound } if config.UserID != userID { return nil, ErrConfigForbidden } total := req.Items.Total() config.Name = req.Name config.Items = req.Items config.TotalPrice = &total config.Notes = req.Notes config.IsTemplate = req.IsTemplate if err := s.configRepo.Update(config); err != nil { return nil, err } return config, nil } func (s *ConfigurationService) Delete(uuid string, userID uint) error { config, err := s.configRepo.GetByUUID(uuid) if err != nil { return ErrConfigNotFound } if config.UserID != userID { return ErrConfigForbidden } return s.configRepo.Delete(config.ID) } func (s *ConfigurationService) Rename(uuid string, userID uint, newName string) (*models.Configuration, error) { config, err := s.configRepo.GetByUUID(uuid) if err != nil { return nil, ErrConfigNotFound } if config.UserID != userID { return nil, ErrConfigForbidden } config.Name = newName if err := s.configRepo.Update(config); err != nil { return nil, err } return config, nil } func (s *ConfigurationService) ListByUser(userID uint, page, perPage int) ([]models.Configuration, int64, error) { if page < 1 { page = 1 } if perPage < 1 || perPage > 100 { perPage = 20 } offset := (page - 1) * perPage return s.configRepo.ListByUser(userID, offset, perPage) } func (s *ConfigurationService) ListTemplates(page, perPage int) ([]models.Configuration, int64, error) { if page < 1 { page = 1 } if perPage < 1 || perPage > 100 { perPage = 20 } offset := (page - 1) * perPage return s.configRepo.ListTemplates(offset, perPage) } // Export configuration as JSON type ConfigExport struct { Name string `json:"name"` Notes string `json:"notes"` Items models.ConfigItems `json:"items"` } func (s *ConfigurationService) ExportJSON(uuid string, userID uint) ([]byte, error) { config, err := s.GetByUUID(uuid, userID) if err != nil { return nil, err } export := ConfigExport{ Name: config.Name, Notes: config.Notes, Items: config.Items, } return json.MarshalIndent(export, "", " ") } func (s *ConfigurationService) ImportJSON(userID uint, data []byte) (*models.Configuration, error) { var export ConfigExport if err := json.Unmarshal(data, &export); err != nil { return nil, err } req := &CreateConfigRequest{ Name: export.Name, Notes: export.Notes, Items: export.Items, } return s.Create(userID, req) }