package usecase import ( "context" "errors" "github.com/gofrs/uuid/v5" "github.com/saveinmed/backend-go/internal/domain" ) // CreateAddress generates an ID and persists a new address. func (s *Service) CreateAddress(ctx context.Context, address *domain.Address) error { // Auto-geocode based on ZIP and Street if address.ZipCode != "" { searchQuery := address.ZipCode + ", " + address.Street + ", " + address.City + ", " + address.State + ", Brazil" lat, lon, err := s.mapbox.Geocode(searchQuery) if err == nil { address.Latitude = lat address.Longitude = lon } } address.ID = uuid.Must(uuid.NewV7()) return s.repo.CreateAddress(ctx, address) } // ListAddresses returns all addresses associated with an entity (user or company). func (s *Service) ListAddresses(ctx context.Context, entityID uuid.UUID) ([]domain.Address, error) { return s.repo.ListAddresses(ctx, entityID) } // UpdateAddress verifies ownership and persists address changes. func (s *Service) UpdateAddress(ctx context.Context, addr *domain.Address, requester *domain.User) error { existing, err := s.repo.GetAddress(ctx, addr.ID) if err != nil { return err } if requester.Role != "Admin" && existing.EntityID != requester.ID && (requester.CompanyID == uuid.Nil || existing.EntityID != requester.CompanyID) { return errors.New("unauthorized to update this address") } // If address details changed, re-geocode if existing.ZipCode != addr.ZipCode || existing.Street != addr.Street || existing.Number != addr.Number { searchQuery := addr.ZipCode + ", " + addr.Street + ", " + addr.City + ", " + addr.State + ", Brazil" lat, lon, err := s.mapbox.Geocode(searchQuery) if err == nil { existing.Latitude = lat existing.Longitude = lon } } existing.Title = addr.Title existing.ZipCode = addr.ZipCode existing.Street = addr.Street existing.Number = addr.Number existing.Complement = addr.Complement existing.District = addr.District existing.City = addr.City existing.State = addr.State return s.repo.UpdateAddress(ctx, existing) } // DeleteAddress removes an address by ID. func (s *Service) DeleteAddress(ctx context.Context, id uuid.UUID) error { return s.repo.DeleteAddress(ctx, id) } // GeocodeAllAddresses resolves coordinates for all addresses missing them. func (s *Service) GeocodeAllAddresses(ctx context.Context) (int, error) { addresses, err := s.repo.ListAllAddresses(ctx) if err != nil { return 0, err } count := 0 for _, addr := range addresses { if addr.Latitude == 0 && addr.Longitude == 0 { searchQuery := addr.ZipCode + ", " + addr.Street + ", " + addr.City + ", " + addr.State + ", Brazil" lat, lon, err := s.mapbox.Geocode(searchQuery) if err == nil { addr.Latitude = lat addr.Longitude = lon _ = s.repo.UpdateAddress(ctx, &addr) count++ // Respect rate limits time.Sleep(100 * time.Millisecond) } } } return count, nil }