package main

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"sync/atomic"
	"time"
)

// buatHandler menghasilkan handler yang menghitung permintaan aktif
// dan memakan 100 milidetik untuk mensimulasikan kerja yang sedang berjalan.
func buatHandler(penghitung *atomic.Int64) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		penghitung.Add(1)
		defer penghitung.Add(-1)
		time.Sleep(100 * time.Millisecond)
		fmt.Fprintln(w, "selesai dilayani")
	})
}

// tungguMasuk menunggu sampai handler pertama benar-benar mulai bekerja.
func tungguMasuk(penghitung *atomic.Int64) {
	for penghitung.Load() == 0 {
		time.Sleep(2 * time.Millisecond)
	}
}

func main() {
	// ===== Bagian 1: Shutdown menunggu permintaan aktif selesai =====
	var aktif atomic.Int64
	ts := httptest.NewServer(buatHandler(&aktif))

	status := make(chan int, 1)
	go func() {
		resp, err := ts.Client().Get(ts.URL)
		if err != nil {
			status <- 0
			return
		}
		io.Copy(io.Discard, resp.Body)
		resp.Body.Close()
		status <- resp.StatusCode
	}()

	tungguMasuk(&aktif)
	fmt.Println("permintaan aktif saat Shutdown dipanggil:", aktif.Load())

	err := ts.Config.Shutdown(context.Background())
	fmt.Println("Shutdown selesai tanpa error:", err == nil)

	kode := <-status
	fmt.Println("permintaan aktif tetap dilayani sampai tuntas, status:", kode)
	fmt.Println("permintaan aktif setelah Shutdown:", aktif.Load())

	_, err = ts.Client().Get(ts.URL)
	fmt.Println("permintaan baru setelah Shutdown ditolak:", err != nil)
	ts.Close()

	// ===== Bagian 2: tenggat drain terlalu pendek membatalkan drain =====
	var aktif2 atomic.Int64
	ts2 := httptest.NewServer(buatHandler(&aktif2))

	go func() {
		resp, err := ts2.Client().Get(ts2.URL)
		if err != nil {
			return
		}
		io.Copy(io.Discard, resp.Body)
		resp.Body.Close()
	}()

	tungguMasuk(&aktif2)

	tenggat, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
	defer cancel()
	err2 := ts2.Config.Shutdown(tenggat)
	fmt.Println("Shutdown dengan tenggat 10 ms gagal:", err2 != nil)
	fmt.Println("error shutdown:", err2)
	fmt.Println("error bertipe deadline:", errors.Is(err2, context.DeadlineExceeded))

	time.Sleep(150 * time.Millisecond) // beri waktu permintaan selesai sendiri
	ts2.Close()
	fmt.Println("server ditutup paksa dengan Close")
}
