package main

import "fmt"

// ===== Domain: tipe data murni tanpa dependensi =====

type Produk struct {
	ID    string
	Nama  string
	Harga int // dalam Rupiah
}

// ===== Data: akses data lewat interface, bukan SQL di handler =====

type RepoProduk interface {
	Cari(id string) (Produk, error)
}

type RepoMemori struct {
	data map[string]Produk
}

func NewRepoMemori() *RepoMemori {
	return &RepoMemori{data: map[string]Produk{
		"P-001": {ID: "P-001", Nama: "Buku Go", Harga: 95000},
		"P-002": {ID: "P-002", Nama: "Mouse Kantor", Harga: 150000},
	}}
}

func (r *RepoMemori) Cari(id string) (Produk, error) {
	p, ok := r.data[id]
	if !ok {
		return Produk{}, fmt.Errorf("produk %s tidak ditemukan", id)
	}
	return p, nil
}

// ===== Service: logika bisnis (diskon member) =====

type LayananProduk struct {
	repo RepoProduk
}

func NewLayananProduk(repo RepoProduk) *LayananProduk {
	return &LayananProduk{repo: repo}
}

func (s *LayananProduk) HargaFinal(id string, member bool) (int, error) {
	p, err := s.repo.Cari(id)
	if err != nil {
		return 0, err
	}
	if member && p.Harga >= 100000 {
		return p.Harga - p.Harga/10, nil
	}
	return p.Harga, nil
}

// ===== Presentation: handler hanya membaca input dan memformat =====

type Permintaan struct {
	ID     string
	Member bool
}

type HandlerProduk struct {
	layanan *LayananProduk
}

func (h *HandlerProduk) Tangani(req Permintaan) string {
	harga, err := h.layanan.HargaFinal(req.ID, req.Member)
	if err != nil {
		return fmt.Sprintf("HTTP 404 — %v", err)
	}
	return fmt.Sprintf(`{"id":%q,"harga":%d}`, req.ID, harga)
}

func main() {
	repo := NewRepoMemori()
	handler := &HandlerProduk{layanan: NewLayananProduk(repo)}

	for _, req := range []Permintaan{
		{ID: "P-001", Member: true},
		{ID: "P-002", Member: true},
		{ID: "P-999", Member: false},
	} {
		fmt.Println(handler.Tangani(req))
	}
}
