import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Locale;

/**
 * Titik masuk API manajemen tugas: HttpServer di alamat loopback dengan port
 * dipilih sistem operasi (port 0), lalu seluruh endpoint diuji lewat HttpClient
 * dalam satu proses yang sama — server dan klien berjalan tanpa jaringan luar.
 */
public class ServerApi {

    public static void main(String[] args) throws Exception {
        TugasRepository repo = new RepositoryMemori();
        HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
        server.createContext("/", new RouterTugas(repo));
        server.start();

        String dasar = "http://127.0.0.1:" + server.getAddress().getPort();
        HttpClient klien = HttpClient.newHttpClient();

        try {
            System.out.println("=== Babak 1: membuat dua tugas ===");
            cetak(klien, "POST", dasar + "/api/tugas",
                    "{\"judul\":\"Belajar HttpServer\",\"pemilik\":\"Budi\",\"tenggat\":\"2026-01-20\"}",
                    null);
            cetak(klien, "POST", dasar + "/api/tugas",
                    "{\"judul\":\"Tulis dokumentasi API\",\"pemilik\":\"Siti\",\"tenggat\":\"2026-02-01\"}",
                    null);

            System.out.println();
            System.out.println("=== Babak 2: membaca daftar dan detail ===");
            cetak(klien, "GET", dasar + "/api/tugas", null, null);
            cetak(klien, "GET", dasar + "/api/tugas/2", null, null);

            System.out.println();
            System.out.println("=== Babak 3: mengubah status tugas 1 ===");
            cetak(klien, "PUT", dasar + "/api/tugas/1",
                    "{\"judul\":\"Belajar HttpServer\",\"pemilik\":\"Budi\","
                            + "\"status\":\"SELESAI\",\"tenggat\":\"2026-01-20\"}",
                    null);

            System.out.println();
            System.out.println("=== Babak 4: permintaan yang ditolak ===");
            cetak(klien, "GET", dasar + "/api/tugas/9", null, null);
            cetak(klien, "GET", dasar + "/api/pengguna", null, null);
            cetak(klien, "POST", dasar + "/api/tugas", "{\"judul\":", "rusak");
            cetak(klien, "POST", dasar + "/api/tugas",
                    "{\"judul\":\"Tugas tanpa pemilik\",\"tenggat\":\"2026-01-22\"}",
                    "tanpa pemilik");
            cetak(klien, "POST", dasar + "/api/tugas",
                    "{\"judul\":\"   \",\"pemilik\":\"Dewi\",\"tenggat\":\"2026-01-25\"}",
                    "judul kosong");
            cetak(klien, "PATCH", dasar + "/api/tugas/1", null, null);

            System.out.println();
            System.out.println("=== Babak 5: menghapus lalu melihat sisa ===");
            cetak(klien, "DELETE", dasar + "/api/tugas/2", null, null);
            cetak(klien, "GET", dasar + "/api/tugas", null, null);
        } finally {
            server.stop(0);
        }
    }

    /**
     * Mengirim satu permintaan lalu mencetak status dan body responsnya.
     * Nomor port sengaja tidak dicetak agar keluaran tetap deterministik.
     */
    private static void cetak(HttpClient klien, String metode, String url,
            String body, String keterangan) throws IOException, InterruptedException {
        HttpRequest.Builder b = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .timeout(Duration.ofSeconds(5));
        if (body == null) {
            b.method(metode, HttpRequest.BodyPublishers.noBody());
        } else {
            b.header("Content-Type", "application/json")
                    .method(metode, HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8));
        }
        HttpResponse<String> respons =
                klien.send(b.build(), HttpResponse.BodyHandlers.ofString());

        String path = URI.create(url).getPath();
        String target = keterangan == null ? path : path + " (" + keterangan + ")";
        System.out.printf(Locale.US, "%-6s %-28s -> %d %s%n",
                metode, target, respons.statusCode(), respons.body());
    }
}
