package com.foxx.androidcast.dev;

import android.util.Log;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;

/** Tiny LAN HTTP server so rebuild.sh can fetch adb connect lines without adb. */
final class DevAdbConnectHttpServer implements Runnable {
    private final AtomicReference<String> payload = new AtomicReference<>("{}");
    private volatile ServerSocket serverSocket;
    private volatile Thread thread;

    void updatePayload(String json) {
        payload.set(json != null ? json : "{}");
    }

    synchronized void start() {
        if (thread != null && thread.isAlive()) {
            return;
        }
        thread = new Thread(this, "DevAdbConnectHttp");
        thread.setDaemon(true);
        thread.start();
    }

    synchronized void stop() {
        Thread local = thread;
        thread = null;
        ServerSocket socket = serverSocket;
        serverSocket = null;
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException ignored) {
            }
        }
        if (local != null) {
            local.interrupt();
        }
    }

    @Override
    public void run() {
        try (ServerSocket socket = new ServerSocket()) {
            socket.setReuseAddress(true);
            socket.bind(new InetSocketAddress(DevAdbConnectInfo.HTTP_PORT));
            serverSocket = socket;
            Log.i(DevAdbConnectInfo.LOG_TAG,
                    "HTTP adb info on :" + DevAdbConnectInfo.HTTP_PORT + "/adb.json");
            while (!Thread.currentThread().isInterrupted()) {
                try (Socket client = socket.accept()) {
                    client.setSoTimeout(5_000);
                    handleClient(client);
                } catch (IOException e) {
                    if (!Thread.currentThread().isInterrupted()) {
                        Log.d(DevAdbConnectInfo.LOG_TAG, "HTTP client error", e);
                    }
                }
            }
        } catch (IOException e) {
            Log.w(DevAdbConnectInfo.LOG_TAG, "HTTP server stopped", e);
        } finally {
            serverSocket = null;
        }
    }

    private void handleClient(Socket client) throws IOException {
        String path = readRequestPath(client);
        String body = payload.get();
        if (body == null || body.isEmpty()) {
            body = "{}";
        }
        if (!"/adb.json".equals(path) && !"/".equals(path)) {
            writeResponse(client, 404, "text/plain", "not found");
            return;
        }
        writeResponse(client, 200, "application/json; charset=utf-8", body);
    }

    private static String readRequestPath(Socket client) throws IOException {
        byte[] buffer = new byte[1024];
        int read = client.getInputStream().read(buffer);
        if (read <= 0) {
            return "/";
        }
        String request = new String(buffer, 0, read, StandardCharsets.US_ASCII);
        int lineEnd = request.indexOf('\n');
        String firstLine = lineEnd >= 0 ? request.substring(0, lineEnd) : request;
        String[] parts = firstLine.split(" ");
        if (parts.length >= 2) {
            return parts[1].trim();
        }
        return "/";
    }

    private static void writeResponse(Socket client, int code, String contentType, String body)
            throws IOException {
        byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
        String status = code == 200 ? "200 OK" : "404 Not Found";
        String headers = "HTTP/1.1 " + status + "\r\n"
                + "Content-Type: " + contentType + "\r\n"
                + "Content-Length: " + bytes.length + "\r\n"
                + "Connection: close\r\n\r\n";
        OutputStream out = client.getOutputStream();
        out.write(headers.getBytes(StandardCharsets.US_ASCII));
        out.write(bytes);
        out.flush();
    }
}
