package acmecert

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"testing"
	"time"

	"mailgoserver/internal/toolbox"
)

// freePort asks the OS for an unused TCP port, mirroring the pattern used elsewhere in
// this codebase's tests for binding to an ephemeral port deterministically.
func freePort(t *testing.T) int {
	t.Helper()
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	return l.Addr().(*net.TCPAddr).Port
}

func waitUntilUp(t *testing.T, url string) {
	t.Helper()
	deadline := time.Now().Add(2 * time.Second)
	for time.Now().Before(deadline) {
		if resp, err := http.Get(url); err == nil {
			resp.Body.Close()
			return
		}
		time.Sleep(10 * time.Millisecond)
	}
	t.Fatalf("server at %s never came up", url)
}

func TestHTTP01ServerHealthEndpointReturns200(t *testing.T) {
	port := freePort(t)
	s := NewHTTP01Server()
	s.Start(fmt.Sprintf("127.0.0.1:%d", port), toolbox.GetLogger("test"))

	url := fmt.Sprintf("http://127.0.0.1:%d/anything", port)
	waitUntilUp(t, url)

	resp, err := http.Get(url)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("expected 200, got %d", resp.StatusCode)
	}
}

func TestHTTP01ServerServesPresentedChallenge(t *testing.T) {
	port := freePort(t)
	s := NewHTTP01Server()
	s.Start(fmt.Sprintf("127.0.0.1:%d", port), toolbox.GetLogger("test"))
	waitUntilUp(t, fmt.Sprintf("http://127.0.0.1:%d/", port))

	if err := s.Present("example.com", "sometoken", "sometoken.keyauth"); err != nil {
		t.Fatal(err)
	}

	resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/.well-known/acme-challenge/sometoken", port))
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK || string(body) != "sometoken.keyauth" {
		t.Fatalf("expected 200 with keyAuth body, got %d %q", resp.StatusCode, body)
	}

	if err := s.CleanUp("example.com", "sometoken", "sometoken.keyauth"); err != nil {
		t.Fatal(err)
	}
	resp2, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/.well-known/acme-challenge/sometoken", port))
	if err != nil {
		t.Fatal(err)
	}
	defer resp2.Body.Close()
	if resp2.StatusCode != http.StatusNotFound {
		t.Fatalf("expected 404 after CleanUp, got %d", resp2.StatusCode)
	}
}
