package routing

import (
	"context"
	"fmt"

	"trip-planner/internal/cache"
	"trip-planner/internal/yandex"
)

// SearchCacheService handles caching and on-demand Yandex /search calls.
type SearchCacheService struct {
	cache  *cache.CacheAside
	yclient *yandex.Client
}

// NewSearchCacheService creates a new search cache service.
func NewSearchCacheService(cacheStore cache.Cache, yclient *yandex.Client) *SearchCacheService {
	return &SearchCacheService{
		cache:   cache.NewCacheAside(cacheStore),
		yclient: yclient,
	}
}

// SearchWithCache performs a route search with caching support.
// It uses the cache-aside pattern: try cache first, then Yandex API, then write back to cache.
func (s *SearchCacheService) SearchWithCache(ctx context.Context, from, to, date string, opts SearchOptions) (*Itinerary, error) {
	// Generate cache key
	searchKey := cache.GetSearchKey(from, to, date)

	// Try to get from cache first
	fetchFunc := func() ([]byte, error) {
		// If we reach here, it's a cache miss - perform on-demand Yandex /search call
		return s.performYandexSearch(ctx, from, to, date, opts)
	}

	// Get or set from cache with appropriate TTL based on far-term flag
	isFarTerm := opts.FarTerm
	data, err := s.cache.GetSearch(ctx, searchKey, fetchFunc, isFarTerm)
	if err != nil {
		return nil, fmt.Errorf("search cache get/set: %w", err)
	}

	// Parse the itinerary from cached data (assuming JSON format)
	var result Itinerary
	if err := parseItineraryFromBytes(data, &result); err != nil {
		return nil, fmt.Errorf("failed to parse itinerary from cache: %w", err)
	}

	return &result, nil
}

// performYandexSearch makes the actual Yandex /search API call.
func (s *SearchCacheService) performYandexSearch(ctx context.Context, from, to, date string, opts SearchOptions) ([]byte, error) {
	// Build query parameters for Yandex /search endpoint
	query := map[string]string{
		"from": from,
		"to":   to,
		"date": date,
	}

	// Execute the Yandex API request
	resp, err := s.yclient.Do(ctx, "GET", "/v3.0/search/", query)
	if err != nil {
		return nil, fmt.Errorf("yandex search failed: %w", err)
	}

	// Convert response to bytes for caching
	return convertResponseToBytes(resp)
}

// parseItineraryFromBytes parses an itinerary from byte data.
func parseItineraryFromBytes(data []byte, result *Itinerary) error {
	// This is a placeholder - in real implementation, this would parse JSON
	// into the Itinerary struct
	if len(data) == 0 {
		return fmt.Errorf("empty data")
	}
	return nil
}

// convertResponseToBytes converts Yandex API response to bytes for caching.
func convertResponseToBytes(resp *yandex.Response) ([]byte, error) {
	// This is a placeholder - in real implementation, this would serialize the response
	if resp == nil {
		return nil, fmt.Errorf("nil response")
	}
	return []byte(`{"search":{"from":"%s","to":"%s"},"segments":[]}`), nil
}
