package main

import (
	"errors"
	"fmt"
)

// ErrSibuk adalah sentinel untuk server yang menolak sementara.
var ErrSibuk = errors.New("server sedang sibuk")

// KlienCadangan mensimulasikan server yang gagal beberapa kali lalu pulih.
type KlienCadangan struct {
	gagal int
}

func (k *KlienCadangan) ambilData() (string, error) {
	if k.gagal > 0 {
		k.gagal--
		return "", fmt.Errorf("ambil data: %w", ErrSibuk)
	}
	return "data utama", nil
}

func ambilDenganRetry(k *KlienCadangan, maksPercobaan int) (string, error) {
	for percobaan := 1; percobaan <= maksPercobaan; percobaan++ {
		hasil, err := k.ambilData()
		if err == nil {
			fmt.Printf("percobaan %d: sukses\n", percobaan)
			return hasil, nil
		}
		fmt.Printf("percobaan %d: %v\n", percobaan, err)
	}
	return "", fmt.Errorf("batal setelah %d percobaan: %w", maksPercobaan, ErrSibuk)
}

func prosesItem(nama string) error {
	if len(nama) < 3 {
		return fmt.Errorf("nama %q terlalu pendek", nama)
	}
	return nil
}

// prosesBatch membandingkan strategi gagal-cepat dengan catat-dan-lanjut.
func prosesBatch(daftar []string, berhentiPadaError bool) (int, []string) {
	sukses := 0
	var masalah []string
	for _, nama := range daftar {
		if err := prosesItem(nama); err != nil {
			masalah = append(masalah, fmt.Sprintf("%q", nama))
			fmt.Printf("  item %q gagal: %v\n", nama, err)
			if berhentiPadaError {
				return sukses, masalah
			}
			continue
		}
		sukses++
	}
	return sukses, masalah
}

func main() {
	k := &KlienCadangan{gagal: 2}
	hasil, err := ambilDenganRetry(k, 3)
	fmt.Println("hasil retry:", hasil, "| err:", err)

	k = &KlienCadangan{gagal: 5}
	hasil, err = ambilDenganRetry(k, 3)
	if err != nil {
		fmt.Println("fallback dipakai: data cadangan")
	}

	daftar := []string{"buku", "pulpen", "ki", "penggaris", "ab"}

	fmt.Println("mode gagal cepat:")
	sukses, masalah := prosesBatch(daftar, true)
	fmt.Printf("  selesai: %d sukses, masalah: %v\n", sukses, masalah)

	fmt.Println("mode catat dan lanjut:")
	sukses, masalah = prosesBatch(daftar, false)
	fmt.Printf("  selesai: %d sukses, masalah: %v\n", sukses, masalah)
}
