import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;

public class TinyHttpServer {

    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(8080);
             var pool = Executors.newVirtualThreadPerTaskExecutor()) {
            System.out.println("Listening on http://localhost:8080/");
            while (true) {
                Socket socket = server.accept();
                pool.submit(() -> handle(socket));
            }
        }
    }

    private static void handle(Socket socket) {
        try (socket;
             var in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.US_ASCII));
             OutputStream out = socket.getOutputStream()) {

            // 1. The request line: METHOD PATH VERSION
            String requestLine = in.readLine();
            if (requestLine == null || requestLine.isBlank()) return;
            String[] parts = requestLine.split(" ");
            if (parts.length != 3) {
                send(out, 400, "Bad Request", "text/plain", "Bad request line\n");
                return;
            }
            String method = parts[0], path = parts[1];
            System.out.println(requestLine);

            // 2. Headers, one per line, until an empty line
            String line;
            int contentLength = 0;
            while ((line = in.readLine()) != null && !line.isEmpty()) {
                System.out.println("  " + line);
                int colon = line.indexOf(':');
                if (colon > 0 && line.substring(0, colon).equalsIgnoreCase("Content-Length")) {
                    contentLength = Integer.parseInt(line.substring(colon + 1).trim());
                }
            }

            // 3. A body only if Content-Length says so (POST, PUT...)
            char[] body = new char[contentLength];
            int read = 0;
            while (read < contentLength) {
                int n = in.read(body, read, contentLength - read);
                if (n < 0) break;
                read += n;
            }

            if (method.equals("GET") && path.equals("/")) {
                send(out, 200, "OK", "text/html; charset=utf-8", "<!doctype html><p>Привет всем! Hello, everyone!</p>\n");
            } else if (method.equals("POST") && path.equals("/echo")) {
                send(out, 200, "OK", "text/plain; charset=utf-8", new String(body, 0, read) + "\n");
            } else {
                send(out, 404, "Not Found", "text/plain; charset=utf-8", "Nothing at " + path + "\n");
            }
        } catch (IOException | RuntimeException e) {
            System.err.println("Connection failed: " + e);
        }
    }

    private static void send(OutputStream out, int status, String reason, String type, String body) throws IOException {
        byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
        String head = "HTTP/1.1 " + status + " " + reason + "\r\n"
                + "Content-Type: " + type + "\r\n"
                + "Content-Length: " + bytes.length + "\r\n"
                + "Connection: close\r\n"
                + "\r\n";
        out.write(head.getBytes(StandardCharsets.US_ASCII));
        out.write(bytes);
        out.flush();
    }
}
