package transport

import (
	"bytes"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"log/slog"
	"os"
	"strings"
	"testing"
)

func newTestLogger(buf *bytes.Buffer) *slog.Logger {
	return slog.New(slog.NewTextHandler(buf, nil))
}

func TestLogHandshakeOK(t *testing.T) {
	var buf bytes.Buffer
	log := newTestLogger(&buf)
	LogHandshakeOK(log, "peer1", "fp123")
	out := buf.String()
	for _, want := range []string{
		"event=mtls.handshake",
		"result=ok",
		"peer=peer1",
		"cert_fp=fp123",
	} {
		if !strings.Contains(out, want) {
			t.Errorf("output missing %q: %s", want, out)
		}
	}
}

func TestLogHandshakeFailed(t *testing.T) {
	var buf bytes.Buffer
	log := newTestLogger(&buf)
	LogHandshakeFailed(log, "peer1", "", errors.New("tls: bad cert"))
	out := buf.String()
	for _, want := range []string{
		"event=mtls.handshake",
		"result=failed",
		"peer=peer1",
		"err=\"tls: bad cert\"",
	} {
		if !strings.Contains(out, want) {
			t.Errorf("output missing %q: %s", want, out)
		}
	}
	if !strings.Contains(out, "level=WARN") {
		t.Errorf("expected WARN level, got: %s", out)
	}
}

func TestLogHandshakeOK_NilLogger(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			t.Fatalf("nil logger panicked: %v", r)
		}
	}()
	LogHandshakeOK(nil, "peer1", "fp123")
}

func TestLogHandshakeFailed_NilLogger(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			t.Fatalf("nil logger panicked: %v", r)
		}
	}()
	LogHandshakeFailed(nil, "peer1", "", errors.New("x"))
}

func TestLogHandshakeFailed_NoErr(t *testing.T) {
	var buf bytes.Buffer
	log := newTestLogger(&buf)
	LogHandshakeFailed(log, "peer1", "fp123", nil)
	out := buf.String()
	if strings.Contains(out, "err=") {
		t.Errorf("expected no err= field when err is nil: %s", out)
	}
	if !strings.Contains(out, "result=failed") {
		t.Errorf("expected result=failed: %s", out)
	}
}

func TestLogHandshakeFromCert_NilCert(t *testing.T) {
	var buf bytes.Buffer
	log := newTestLogger(&buf)
	LogHandshakeFromCert(log, "peer1", nil)
	out := buf.String()
	if !strings.Contains(out, "result=ok") {
		t.Errorf("expected result=ok: %s", out)
	}
	if !strings.Contains(out, "peer=peer1") {
		t.Errorf("expected peer=peer1: %s", out)
	}
}

func TestLogHandshakeFromCert_WithCert(t *testing.T) {
	var buf bytes.Buffer
	log := newTestLogger(&buf)
	dir := t.TempDir()
	certPath, _, _ := generateTestCerts(t, dir, "localhost")
	certPEM, err := os.ReadFile(certPath)
	if err != nil {
		t.Fatalf("read cert: %v", err)
	}
	block, _ := pem.Decode(certPEM)
	if block == nil {
		t.Fatal("pem.Decode: no cert block")
	}
	leaf, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		t.Fatalf("ParseCertificate: %v", err)
	}
	LogHandshakeFromCert(log, "peer-cert", leaf)
	out := buf.String()
	if !strings.Contains(out, "result=ok") {
		t.Errorf("expected result=ok: %s", out)
	}
	expectedFP := FingerprintOfCert(leaf)
	if !strings.Contains(out, "cert_fp="+expectedFP) {
		t.Errorf("expected cert_fp=%s in: %s", expectedFP, out)
	}
}

func TestFingerprintOfCert_Nil(t *testing.T) {
	if got := FingerprintOfCert(nil); got != "" {
		t.Errorf("FingerprintOfCert(nil) = %q, want empty", got)
	}
}
