package main

import (
	"context"
	"log"
	"net/http"
	"os"

	"github.com/go-redis/redis/v8"

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

func main() {
	redisClient := initRedis()
	router := routing.NewGraph()
	m := metrics.New()

	apiKey := os.Getenv("YANDEX_API_KEY")
	if apiKey == "" {
		log.Fatal("YANDEX_API_KEY environment variable is not set")
	}
	yandexClient := yandex.NewClient(apiKey, yandex.WithMetrics(m))

	handlerCtx := NewHandlerContext(redisClient, router, yandexClient, m)

	// Cache warm-up: load city directory into Redis cache
	// ensures the API functions correctly on cold start and after cache expiry
	loadCityDirectoryIntoCache(context.Background(), handlerCtx.Cache)

	http.HandleFunc("/v1/cities", makeHandler(CityAutocomplete, handlerCtx))
	http.HandleFunc("/v1/cities/", makeHandler(CityStations, handlerCtx))
	http.HandleFunc("/v1/routes/search", makeHandler(RouteSearch, handlerCtx))
	http.HandleFunc("/v1/routes/", makeHandler(RouteGeoJSON, handlerCtx))
	http.HandleFunc("/v1/stations/", makeHandler(StationStatus, handlerCtx))
	http.HandleFunc("/internal/admin/stations/", makeHandler(AdminStationStatus, handlerCtx))
	http.HandleFunc("/metrics", makeHandler(MetricsHandler, handlerCtx))

	// User preferences routes
	http.HandleFunc("/v1/preferences/saved-cities", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			GetSavedCities(handlerCtx, w, r)
		case http.MethodPost:
			AddSavedCity(handlerCtx, w, r)
		default:
			http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		}
	})
	http.HandleFunc("/v1/preferences/saved-cities/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodDelete {
			RemoveSavedCity(handlerCtx, w, r)
		} else {
			http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		}
	})
	http.HandleFunc("/v1/preferences/search-history", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			GetSearchHistory(handlerCtx, w, r)
		case http.MethodPost:
			AddSearchHistory(handlerCtx, w, r)
		default:
			http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		}
	})

	// Serve static files from static/ directory
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	// Serve frontend
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" || r.URL.Path == "/index.html" {
			http.ServeFile(w, r, "static/index.html")
			return
		}
		http.NotFound(w, r)
	})

	log.Println("Trip Planner API starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

// initRedis initializes a Redis client connection.
func initRedis() *redis.Client {
	redisAddr := os.Getenv("REDIS_ADDR")
	if redisAddr == "" {
		redisAddr = "localhost:6379"
	}
	rdb := redis.NewClient(&redis.Options{
		Addr:     redisAddr,
		Password: "",
		DB:       0,
	})
	return rdb
}

// loadCityDirectoryIntoCache loads city data into Redis cache from stored records.
// ensures the API functions correctly on cold start and after cache expiry.
func loadCityDirectoryIntoCache(ctx context.Context, cache cache.Cache) {
	// In a full implementation, would load from Postgres directory
	// For now, this is a no-op since we don't have Postgres integration
	_ = ctx
	_ = cache
}

// makeHandler wraps a standalone handler function (which takes *HandlerContext)
// into an http.HandlerFunc (which takes http.ResponseWriter and *http.Request).
func makeHandler(handler func(*HandlerContext, http.ResponseWriter, *http.Request), hc *HandlerContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		handler(hc, w, r)
	}
}
