package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type Produk struct {
	ID       string   `json:"id" xml:"id,attr"`
	Nama     string   `json:"nama,omitempty" xml:"nama"`
	Harga    int      `json:"harga,omitempty" xml:"-"`
	Aktif    bool     `json:"aktif,omitempty" xml:"aktif"`
	Tag      []string `json:"tag,omitempty" xml:"tag"`
	Stok     *int     `json:"stok,omitempty" xml:"-"`
	Rahasia  string   `json:"-" xml:"-"`
	Kategori string   `json:"kategori,omitempty" xml:"kategori"`
}

func main() {
	// Semua field opsional bernilai zero: omitempty memangkasnya.
	p := Produk{ID: "P-01", Nama: "Buku Go", Harga: 95000, Aktif: true}
	stok := 0 // pointer ke nol tetap ikut output
	p.Stok = &stok
	data, err := json.Marshal(p)
	if err != nil {
		fmt.Println("marshal gagal:", err)
		return
	}
	fmt.Println(string(data))

	// Hanya ID terisi: field lain bernilai zero dan hilang.
	data2, _ := json.Marshal(Produk{ID: "P-02"})
	fmt.Println(string(data2))

	// Decode: pencocokan nama field tidak peka huruf besar-kecil,
	// field yang tidak dikenal (stok, berat, diskon) diabaikan.
	sumber := []byte(`{"ID":"P-03","NAMA":"Kopi","harga":15000,"stok":7,"berat":250,"diskon":true}`)
	var p3 Produk
	if err := json.Unmarshal(sumber, &p3); err != nil {
		fmt.Println("unmarshal gagal:", err)
		return
	}
	fmt.Printf("hasil decode: ID=%s Nama=%s Harga=%d", p3.ID, p3.Nama, p3.Harga)
	if p3.Stok != nil {
		fmt.Printf(" stok=%d", *p3.Stok)
	}
	fmt.Println()

	// reflect membaca struct tag saat runtime.
	t := reflect.TypeOf(p)
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		fmt.Printf("field %-8s json=%-18q xml=%q\n", f.Name, f.Tag.Get("json"), f.Tag.Get("xml"))
	}
}
