package main

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

// TestIntegrationShortenRedirectStats menjalankan alur shorten →
// redirect → stats melawan PostgreSQL sungguhan. Tanpa
// TEST_DATABASE_URL, test ini dilewati (skip) supaya `go test ./...`
// tetap lulus di lingkungan offline:
//
//	TEST_DATABASE_URL=postgres://user:pass@localhost:5432/urls?sslmode=disable \
//	  go test -v -run Integration ./...
func TestIntegrationShortenRedirectStats(t *testing.T) {
	dsn := os.Getenv("TEST_DATABASE_URL")
	if dsn == "" {
		t.Skip("TEST_DATABASE_URL kosong: integration test membutuhkan PostgreSQL aktif")
	}

	ctx := context.Background()
	db, err := OpenDatabase(ctx, dsn)
	if err != nil {
		t.Fatalf("membuka database: %v", err)
	}
	defer db.Close()

	if err := RunMigrations(ctx, db); err != nil {
		t.Fatalf("menjalankan migration: %v", err)
	}

	// Bersihkan data test sebelumnya supaya test dapat diulang.
	if _, err := db.ExecContext(ctx, `TRUNCATE urls`); err != nil {
		t.Fatalf("membersihkan tabel urls: %v", err)
	}

	gen := &genStub{daftar: []string{"b1Gk0D3"}}
	svc := NewShortenService(NewPostgresURLRepository(db), gen, RealClock{})
	ts := httptest.NewServer(NewRouter(svc, "http://short.test/"))
	defer ts.Close()

	klien := &http.Client{CheckRedirect: func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}}

	resp, err := http.Post(ts.URL+"/shorten", "application/json",
		strings.NewReader(`{"url":"https://example.com/integrasi"}`))
	if err != nil {
		t.Fatalf("POST /shorten: %v", err)
	}
	resp.Body.Close()
	if resp.StatusCode != http.StatusCreated {
		t.Fatalf("POST /shorten status = %d, ingin 201", resp.StatusCode)
	}

	for i := 1; i <= 2; i++ {
		resp2, err := klien.Get(ts.URL + "/b1Gk0D3")
		if err != nil {
			t.Fatalf("GET /b1Gk0D3 ke-%d: %v", i, err)
		}
		resp2.Body.Close()
		if resp2.StatusCode != http.StatusFound {
			t.Fatalf("redirect ke-%d status = %d, ingin 302", i, resp2.StatusCode)
		}
		if loc := resp2.Header.Get("Location"); loc != "https://example.com/integrasi" {
			t.Fatalf("redirect ke-%d Location = %q, ingin URL asli", i, loc)
		}
	}

	resp3, err := http.Get(ts.URL + "/stats/b1Gk0D3")
	if err != nil {
		t.Fatalf("GET /stats/b1Gk0D3: %v", err)
	}
	defer resp3.Body.Close()
	if resp3.StatusCode != http.StatusOK {
		t.Fatalf("GET /stats status = %d, ingin 200", resp3.StatusCode)
	}
	var stat struct {
		Clicks int64 `json:"clicks"`
	}
	if err := json.NewDecoder(resp3.Body).Decode(&stat); err != nil {
		t.Fatalf("mendekode body stats: %v", err)
	}
	if stat.Clicks != 2 {
		t.Errorf("klik = %d, ingin 2 setelah dua redirect (UPDATE atomik)", stat.Clicks)
	}
}
