package main

import (
	"fmt"
	"maps"
	"slices"
	"strings"
)

// ===== MODULE inventaris (seolah-olah internal/inventaris) =====
// Hanya API publik modul ini yang boleh dipakai modul lain.

type LayananInventaris struct {
	stok map[string]int
}

func NewLayananInventaris() *LayananInventaris {
	return &LayananInventaris{stok: map[string]int{
		"Buku Go": 5,
		"Mouse":   2,
	}}
}

func (l *LayananInventaris) AmbilStok(nama string, qty int) error {
	sisa, ok := l.stok[nama]
	if !ok {
		return fmt.Errorf("produk %q tidak dikenal", nama)
	}
	if qty > sisa {
		return fmt.Errorf("stok %q tersisa %d, diminta %d", nama, sisa, qty)
	}
	l.stok[nama] = sisa - qty
	return nil
}

func (l *LayananInventaris) Laporan() string {
	bagian := make([]string, 0, len(l.stok))
	for _, nama := range slices.Sorted(maps.Keys(l.stok)) {
		bagian = append(bagian, fmt.Sprintf("%s=%d", nama, l.stok[nama]))
	}
	return strings.Join(bagian, ", ")
}

// ===== MODULE pesanan (seolah-olah internal/pesanan) =====
// Modul pesanan tidak mengakses data inventaris secara langsung.
// Modul ini hanya mendefinisikan gerbang (interface) yang dibutuhkannya.

type GerbangStok interface {
	AmbilStok(nama string, qty int) error
}

type LayananPesanan struct {
	gerbang GerbangStok
}

func (l *LayananPesanan) Buat(nomor, produk string, qty int) string {
	if err := l.gerbang.AmbilStok(produk, qty); err != nil {
		return fmt.Sprintf("%s DITOLAK: %v", nomor, err)
	}
	return fmt.Sprintf("%s OK: %s x%d", nomor, produk, qty)
}

// ===== main: satu binary, dua modul berinteraksi lewat interface =====

func main() {
	inventaris := NewLayananInventaris()
	pesanan := &LayananPesanan{gerbang: inventaris}

	fmt.Println(pesanan.Buat("PSN-1", "Buku Go", 2))
	fmt.Println(pesanan.Buat("PSN-2", "Mouse", 5))
	fmt.Println(pesanan.Buat("PSN-3", "Buku Go", 4))
	fmt.Println("stok akhir:", inventaris.Laporan())
}
