package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
)

// allowedOrigin adalah satu-satunya origin yang dipercaya server.
const allowedOrigin = "https://app.example.com"

// corsMiddleware menyetel header CORS dan menjawab preflight OPTIONS.
func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		origin := r.Header.Get("Origin")
		if origin == allowedOrigin {
			// Nilai spesifik, bukan "*": aman dipakai bersama credentials.
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Add("Vary", "Origin")
		}
		if r.Method == http.MethodOptions {
			// Preflight: browser menanyakan izin sebelum request sungguhan.
			w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
			w.Header().Set("Access-Control-Max-Age", "600")
			w.WriteHeader(http.StatusNoContent)
			return
		}
		next.ServeHTTP(w, r)
	})
}

// cetakHeader mencetak satu header respons, atau "(tidak diset)" bila kosong.
func cetakHeader(rec *httptest.ResponseRecorder, key string) {
	v := rec.Header().Get(key)
	if v == "" {
		v = "(tidak diset)"
	}
	fmt.Println(key+":", v)
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /api/salam", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Halo dari API")
	})
	handler := corsMiddleware(mux)

	// Skenario 1: preflight OPTIONS dari origin yang diizinkan.
	req := httptest.NewRequest(http.MethodOptions, "/api/salam", nil)
	req.Header.Set("Origin", allowedOrigin)
	req.Header.Set("Access-Control-Request-Method", "POST")
	req.Header.Set("Access-Control-Request-Headers", "Content-Type")
	rec := httptest.NewRecorder()
	handler.ServeHTTP(rec, req)

	fmt.Println("== Skenario 1: preflight OPTIONS ==")
	fmt.Println("status:", rec.Code)
	cetakHeader(rec, "Access-Control-Allow-Origin")
	cetakHeader(rec, "Access-Control-Allow-Methods")
	cetakHeader(rec, "Access-Control-Allow-Headers")
	cetakHeader(rec, "Access-Control-Max-Age")
	cetakHeader(rec, "Vary")

	// Skenario 2: GET biasa dari origin yang diizinkan.
	req = httptest.NewRequest(http.MethodGet, "/api/salam", nil)
	req.Header.Set("Origin", allowedOrigin)
	rec = httptest.NewRecorder()
	handler.ServeHTTP(rec, req)

	fmt.Println()
	fmt.Println("== Skenario 2: GET dari origin diizinkan ==")
	fmt.Println("status:", rec.Code)
	cetakHeader(rec, "Access-Control-Allow-Origin")
	fmt.Println("body:", strings.TrimSpace(rec.Body.String()))

	// Skenario 3: GET dari origin asing — header izin tidak diset.
	req = httptest.NewRequest(http.MethodGet, "/api/salam", nil)
	req.Header.Set("Origin", "https://jahat.example.net")
	rec = httptest.NewRecorder()
	handler.ServeHTTP(rec, req)

	fmt.Println()
	fmt.Println("== Skenario 3: GET dari origin asing ==")
	fmt.Println("status:", rec.Code)
	cetakHeader(rec, "Access-Control-Allow-Origin")
	fmt.Println("body tetap terkirim ke browser, namun JavaScript diblokir")
}
