package main

import (
	"errors"
	"fmt"
	"strings"
)

// ===== Domain: tipe data inti =====

type Item struct {
	Nama  string
	Harga int
}

// ===== Lapisan Service / Use Case =====
// Interface repository didefinisikan DI SINI (dependency inversion):
// service menentukan kontrak penyimpanan yang dibutuhkannya.

type RepoItem interface {
	Simpan(item Item) error
}

var ErrItemKosong = errors.New("nama item tidak boleh kosong")

type UseCasePesan struct {
	repo RepoItem
}

func NewUseCasePesan(repo RepoItem) *UseCasePesan {
	return &UseCasePesan{repo: repo}
}

func (u *UseCasePesan) BuatPesan(nama string, harga int) (Item, error) {
	if strings.TrimSpace(nama) == "" {
		return Item{}, ErrItemKosong
	}
	item := Item{Nama: nama, Harga: harga}
	if err := u.repo.Simpan(item); err != nil {
		return Item{}, fmt.Errorf("gagal menyimpan pesanan: %w", err)
	}
	return item, nil
}

// ===== Lapisan Data: adapter penyimpanan =====

type RepoMemori struct {
	items []Item
}

func (r *RepoMemori) Simpan(item Item) error {
	r.items = append(r.items, item)
	return nil
}

// ===== Lapisan Presentation: handler =====

type HandlerPesan struct {
	useCase *UseCasePesan
}

func (h *HandlerPesan) Buat(nama string, harga int) string {
	fmt.Printf("[handler] menerima permintaan pesanan %q\n", nama)
	item, err := h.useCase.BuatPesan(nama, harga)
	if err != nil {
		fmt.Printf("[handler] error naik ke atas: %v\n", err)
		return "400 Bad Request"
	}
	fmt.Printf("[handler] merakit response 201 untuk item %q\n", item.Nama)
	return "201 Created"
}

func main() {
	repo := &RepoMemori{}
	handler := &HandlerPesan{useCase: NewUseCasePesan(repo)}

	fmt.Println(handler.Buat("Buku Go", 95000))
	fmt.Println(handler.Buat("", 0))
	fmt.Println(handler.Buat("Mouse Kantor", 150000))
	fmt.Printf("isi repository: %d item\n", len(repo.items))
}
