package diyanetprovider import ( "context" "errors" "fmt" "time" "prayertimes/pkg/prayer" ) type APIProvider interface { Get(ctx context.Context, locationID string) ([]prayer.Times, error) GetByCoords(ctx context.Context, coords prayer.Coordinates) ([]prayer.Times, error) SearchLocations(ctx context.Context, query string) ([]prayer.Location, error) } type FallbackProvider interface { GetByCoords(ctx context.Context, coords prayer.Coordinates) ([]prayer.Times, error) } type Provider struct { api APIProvider fallback FallbackProvider timeout time.Duration } func New(api APIProvider, fallback FallbackProvider) Provider { return Provider{ api: api, fallback: fallback, timeout: time.Second, } } func (p Provider) SearchLocations(ctx context.Context, query string) ([]prayer.Location, error) { locations, err := p.api.SearchLocations(ctx, query) if err != nil { return nil, fmt.Errorf("failed to search locations from api provider: %w", err) } return locations, nil } func (p Provider) Get(ctx context.Context, locationID string) ([]prayer.Times, error) { ctxWithTimeout, cancel := context.WithTimeout(ctx, p.timeout) defer cancel() times, err := p.api.Get(ctxWithTimeout, locationID) if err != nil { return nil, fmt.Errorf("failed to get prayer times from api provider: %w", err) } if len(times) == 0 { return nil, fmt.Errorf("failed to get prayer times from api provider: %w", errors.New("empty prayer times result")) } return times, nil } func (p Provider) GetByCoords(ctx context.Context, coords prayer.Coordinates) ([]prayer.Times, error) { ctxWithTimeout, cancel := context.WithTimeout(ctx, p.timeout) defer cancel() times, err := p.api.GetByCoords(ctxWithTimeout, coords) if err == nil && len(times) > 0 { return times, nil } fallbackTimes, fallbackErr := p.fallback.GetByCoords(ctx, coords) if fallbackErr != nil { if err != nil { return nil, fmt.Errorf("failed to get prayer times from fallback provider: %w", errors.Join(err, fallbackErr)) } return nil, fmt.Errorf("failed to get prayer times from fallback provider: %w", fallbackErr) } if len(fallbackTimes) == 0 { return nil, fmt.Errorf("failed to get prayer times from fallback provider: %w", errors.New("empty prayer times result")) } return fallbackTimes, nil }