package urlshortener

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func TestURLShortenerFlow(t *testing.T) {
	// Initialize memory store and server
	store := NewMemoryStore()
	server := NewServer(store)

	mux := http.NewServeMux()
	server.RegisterRoutes(mux)

	// 1. Test POST /shorten
	longURL := "https://golang.org/doc/effective_go"
	reqBody, _ := json.Marshal(ShortenRequest{URL: longURL})
	
	req := httptest.NewRequest("POST", "/shorten", bytes.NewBuffer(reqBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	
	mux.ServeHTTP(w, req)

	if w.Code != http.StatusCreated {
		t.Fatalf("Expected status Created (201), got %d", w.Code)
	}

	var resp ShortenResponse
	err := json.NewDecoder(w.Body).Decode(&resp)
	if err != nil {
		t.Fatalf("Failed to parse shorten response: %v", err)
	}

	if resp.ShortCode == "" {
		t.Error("Expected short_code to not be empty")
	}
	if !strings.Contains(resp.ShortURL, resp.ShortCode) {
		t.Errorf("Expected short_url %q to contain short_code %q", resp.ShortURL, resp.ShortCode)
	}

	// 2. Test GET /{short_code} (Redirect)
	redirectReq := httptest.NewRequest("GET", "/"+resp.ShortCode, nil)
	redirectW := httptest.NewRecorder()
	
	mux.ServeHTTP(redirectW, redirectReq)

	if redirectW.Code != http.StatusTemporaryRedirect {
		t.Errorf("Expected redirect status (307), got %d", redirectW.Code)
	}

	location := redirectW.Header().Get("Location")
	if location != longURL {
		t.Errorf("Expected Location header %q, got %q", longURL, location)
	}

	// 3. Test GET /metrics/{short_code}
	metricsReq := httptest.NewRequest("GET", "/metrics/"+resp.ShortCode, nil)
	metricsW := httptest.NewRecorder()
	
	mux.ServeHTTP(metricsW, metricsReq)

	if metricsW.Code != http.StatusOK {
		t.Fatalf("Expected metrics status (200), got %d", metricsW.Code)
	}

	var metrics URLMetrics
	err = json.NewDecoder(metricsW.Body).Decode(&metrics)
	if err != nil {
		t.Fatalf("Failed to parse metrics: %v", err)
	}

	if metrics.Hits != 1 {
		t.Errorf("Expected hits to be 1, got %d", metrics.Hits)
	}
	if metrics.OriginalURL != longURL {
		t.Errorf("Expected original URL %q, got %q", longURL, metrics.OriginalURL)
	}

	// 4. Test GET /nonexistent (404)
	missingReq := httptest.NewRequest("GET", "/abcde", nil)
	missingW := httptest.NewRecorder()
	
	mux.ServeHTTP(missingW, missingReq)

	if missingW.Code != http.StatusNotFound {
		t.Errorf("Expected 404 for missing code, got %d", missingW.Code)
	}
}
