package urlshortener

import (
	"net/http"
	"encoding/json"
	"math/rand"
)

// Server holds dependencies for our HTTP server.
type Server struct {
	Store URLStore
}

// NewServer creates a new Server instance.
func NewServer(store URLStore) *Server {
	return &Server{
		Store: store,
	}
}

// RegisterRoutes sets up HTTP routing.
// Note: In Go 1.22+, you can define methods and variables directly in the routing pattern:
// e.g. mux.HandleFunc("POST /shorten", s.HandleShorten)
// e.g. mux.HandleFunc("GET /{short_code}", s.HandleRedirect)
func (s *Server) RegisterRoutes(mux *http.ServeMux) {
	mux.HandleFunc("POST /shorten", s.HandleShorten)
	mux.HandleFunc("GET /{short_code}", s.HandleRedirect)
	mux.HandleFunc("GET /metrics/{short_code}", s.HandleMetrics)
	// TODO: Register your route handlers using the patterns above.
}

type ShortenRequest struct {
	URL string `json:"url"`
}

type ShortenResponse struct {
	ShortCode string `json:"short_code"`
	ShortURL  string `json:"short_url"`
}

func generateShortCode() string {
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
	b := make([]byte, 5)
	for i := range b {
		b[i] = charset[rand.Intn(len(charset))]
	}
	return string(b)
}

// HandleShorten processes a request to shorten a URL.
func (s *Server) HandleShorten(w http.ResponseWriter, r *http.Request) {
	var data ShortenRequest
	err := json.NewDecoder(r.Body).Decode(&data)
	if err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}
	shortCode := generateShortCode()
	err = s.Store.Save(shortCode, data.URL)
	if err != nil {
		http.Error(w, "Failed to save URL", http.StatusInternalServerError)
		return
	}
	var resp ShortenResponse
	resp.ShortCode = shortCode
	resp.ShortURL = "http://localhost:8080/" + shortCode

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(resp)

	// TODO: Implement.
	// 1. Decode the JSON body into ShortenRequest. If invalid, write http.StatusBadRequest (400).
	// 2. Generate a random short code (e.g. 5 random alphabetic characters).
	// 3. Save the mapping using s.Store.Save.
	// 4. Send back a JSON response with the short code and the full short URL (e.g. http://localhost:8080/{short_code}).
	//    Write http.StatusCreated (201).
}

// HandleRedirect handles requests redirecting the client to their destination.
func (s *Server) HandleRedirect(w http.ResponseWriter, r *http.Request) {
	shortCode := r.PathValue("short_code")
	originalURL, err := s.Store.Get(shortCode)
	if err != nil {
		http.Error(w, "URL not found", http.StatusNotFound)
		return
	}
	err = s.Store.IncrementHits(shortCode)
	if err != nil {
		http.Error(w, "Failed to increment hits", http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, originalURL, http.StatusTemporaryRedirect)
	// TODO: Implement.
	// 1. Extract the "short_code" path value (Hint: use r.PathValue("short_code")).
	// 2. Lookup the original URL using s.Store.Get.
	// 3. If missing, return http.StatusNotFound (404).
	// 4. Increment the metrics hit counter using s.Store.IncrementHits.
	// 5. Redirect the client to the original URL using http.Redirect with http.StatusTemporaryRedirect (307).
}

// HandleMetrics returns hit statistics for a shortened URL.
func (s *Server) HandleMetrics(w http.ResponseWriter, r *http.Request) {
	shortCode := r.PathValue("short_code")
	metrics, err := s.Store.GetMetrics(shortCode)
	if err != nil {
		http.Error(w, "URL not found", http.StatusNotFound)
		return
	}
	json.NewEncoder(w).Encode(metrics)
	// TODO: Implement.
	// 1. Extract the "short_code" path value.
	// 2. Load metrics using s.Store.GetMetrics.
	// 3. If missing, return http.StatusNotFound (404).
	// 4. Encode and return the metrics struct as JSON.
}
