package main

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

// ringkas mengambil satu URL dan meringkas status serta isi responsnya.
func ringkas(c *http.Client, url string) string {
	resp, err := c.Get(url)
	if err != nil {
		return "ditolak"
	}
	defer resp.Body.Close()
	isi, _ := io.ReadAll(resp.Body)
	return fmt.Sprintf("%s (%s)", resp.Status, strings.TrimSpace(string(isi)))
}

func main() {
	// ready menyatakan apakah instance siap menerima trafik baru.
	var ready atomic.Bool
	ready.Store(true)

	mux := http.NewServeMux()
	mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
		if !ready.Load() {
			w.WriteHeader(http.StatusServiceUnavailable)
			fmt.Fprintln(w, "siap: tidak")
			return
		}
		fmt.Fprintln(w, "siap: ya")
	})
	mux.HandleFunc("GET /proses", func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(100 * time.Millisecond) // simulasi pekerjaan yang sedang berjalan
		fmt.Fprintln(w, "pekerjaan selesai")
	})

	ts := httptest.NewServer(mux)

	// Fase 1: readiness masih naik, load balancer boleh mengirim trafik.
	fmt.Println("health check awal      :", ringkas(ts.Client(), ts.URL+"/healthz"))

	// Fase 2: turunkan readiness lebih dulu sebelum shutdown.
	ready.Store(false)
	fmt.Println("health setelah turun   :", ringkas(ts.Client(), ts.URL+"/healthz"))

	// Fase 3: satu request sedang diproses saat sinyal berhenti datang.
	hasil := make(chan string, 1)
	go func() {
		hasil <- ringkas(ts.Client(), ts.URL+"/proses")
	}()
	time.Sleep(20 * time.Millisecond) // pastikan request sudah masuk handler

	// Fase 4: drain — tolak trafik baru, tunggu trafik aktif tuntas.
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	err := ts.Config.Shutdown(ctx)
	fmt.Println("Shutdown error         :", err)

	// Fase 5: request aktif tuntas; request baru ditolak di pintu masuk.
	fmt.Println("request aktif selesai  :", <-hasil)
	_, errBaru := ts.Client().Get(ts.URL + "/healthz")
	fmt.Println("request baru ditolak   :", errBaru != nil)

	ts.Close()
}
