package main

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"
)

type WaktuBeku struct {
	Waktu time.Time
}

// MarshalJSON mengubah WaktuBeku menjadi string berformat "2006-01-02 15:04".
func (w WaktuBeku) MarshalJSON() ([]byte, error) {
	stempel := w.Waktu.Format("2006-01-02 15:04")
	return []byte(`"` + stempel + `"`), nil
}

// UnmarshalJSON mem-parsing string "2006-01-02 15:04" kembali menjadi waktu.
func (w *WaktuBeku) UnmarshalJSON(data []byte) error {
	t, err := time.Parse("2006-01-02 15:04", strings.Trim(string(data), `"`))
	if err != nil {
		return fmt.Errorf("WaktuBeku: format harus 2006-01-02 15:04: %w", err)
	}
	w.Waktu = t
	return nil
}

// Uang menyimpan nilai dalam satuan sen agar perhitungan tetap bulat.
type Uang struct {
	Sen int64
}

func (u Uang) MarshalJSON() ([]byte, error) {
	return []byte(strconv.FormatInt(u.Sen, 10)), nil
}

func (u *Uang) UnmarshalJSON(data []byte) error {
	n, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64)
	if err != nil {
		return fmt.Errorf("Uang: harus angka bulat sen: %w", err)
	}
	u.Sen = n
	return nil
}

type Transaksi struct {
	ID        string
	Waktu     WaktuBeku
	Jumlah    Uang
	Pelanggan string
}

func main() {
	t := Transaksi{
		ID:        "T-001",
		Waktu:     WaktuBeku{Waktu: time.Date(2026, 1, 15, 8, 30, 0, 0, time.UTC)},
		Jumlah:    Uang{Sen: 125050},
		Pelanggan: "Budi",
	}
	data, err := json.MarshalIndent(t, "", "  ")
	if err != nil {
		fmt.Println("marshal gagal:", err)
		return
	}
	fmt.Println(string(data))

	var t2 Transaksi
	sumber := []byte(`{"ID":"T-002","Waktu":"2026-01-15 09:00","Jumlah":99000,"Pelanggan":"Siti"}`)
	if err := json.Unmarshal(sumber, &t2); err != nil {
		fmt.Println("unmarshal gagal:", err)
		return
	}
	fmt.Printf("hasil decode: %+v\n", t2)

	sumber2 := []byte(`{"ID":"T-003","Waktu":"15/01/2026","Jumlah":50000,"Pelanggan":"Rina"}`)
	err = json.Unmarshal(sumber2, &t2)
	fmt.Println("galat format:", err)
}
