package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
)

// Config menampung seluruh konfigurasi aplikasi contoh.
type Config struct {
	Host   string `json:"host"`
	Port   int    `json:"port"`
	Debug  bool   `json:"debug"`
	Prefix string `json:"prefix"`
}

func main() {
	port := flag.Int("port", 0, "nomor port (0 berarti tidak diisi)")
	flag.Parse()

	// Lapis 1: nilai default.
	cfg := Config{Host: "localhost", Port: 8080, Debug: false, Prefix: "app"}
	fmt.Printf("default : host=%s port=%d debug=%v\n", cfg.Host, cfg.Port, cfg.Debug)

	// Lapis 2: nilai dari berkas konfigurasi JSON menimpa default.
	berkas := tulisBerkasDemo()
	data, err := os.ReadFile(berkas)
	if err != nil {
		fmt.Fprintln(os.Stderr, "gagal membaca berkas:", err)
		os.Exit(1)
	}
	fmt.Println("isi berkas:")
	fmt.Println(string(data))

	var dariFile Config
	if err := json.Unmarshal(data, &dariFile); err != nil {
		fmt.Fprintln(os.Stderr, "gagal mengurai JSON:", err)
		os.Exit(1)
	}
	// Overlay: timpa hanya field yang terisi di berkas.
	if dariFile.Host != "" {
		cfg.Host = dariFile.Host
	}
	if dariFile.Port != 0 {
		cfg.Port = dariFile.Port
	}
	if dariFile.Debug {
		cfg.Debug = dariFile.Debug
	}
	fmt.Printf("berkas  : host=%s port=%d debug=%v\n", cfg.Host, cfg.Port, cfg.Debug)

	// Lapis 3: variabel lingkungan menimpa berkas.
	envPort := os.Getenv("APP_PORT")
	fmt.Println("env     : APP_PORT=" + envPort)
	if p, err := strconv.Atoi(envPort); err == nil && p != 0 {
		cfg.Port = p
	}

	// Lapis 4: flag paling tinggi prioritasnya.
	if *port != 0 {
		fmt.Printf("flag    : -port=%d\n", *port)
		cfg.Port = *port
	} else {
		fmt.Println("flag    : (tidak diisi)")
	}

	fmt.Printf("aktif   : host=%s port=%d debug=%v prefix=%s\n", cfg.Host, cfg.Port, cfg.Debug, cfg.Prefix)
}

// tulisBerkasDemo membuat berkas config.json di direktori sementara,
// lalu mengembalikan lokasinya untuk dibaca kembali.
func tulisBerkasDemo() string {
	dir, err := os.MkdirTemp("", "config-demo")
	if err != nil {
		fmt.Fprintln(os.Stderr, "gagal membuat direktori sementara:", err)
		os.Exit(1)
	}
	path := filepath.Join(dir, "config.json")

	isi, err := json.MarshalIndent(Config{Host: "db.example.com", Port: 5432, Debug: true}, "", "  ")
	if err != nil {
		fmt.Fprintln(os.Stderr, "gagal membuat JSON:", err)
		os.Exit(1)
	}
	if err := os.WriteFile(path, isi, 0o600); err != nil {
		fmt.Fprintln(os.Stderr, "gagal menulis berkas:", err)
		os.Exit(1)
	}
	return path
}
