package encoder

import (
	"encoding/base64"
	"os"
	"strings"
	"testing"
)

func testKeyring(t *testing.T) string {
	t.Helper()
	path := t.TempDir() + "/pubring.mix"
	var content strings.Builder
	for i, name := range []string{"entry", "middle", "exit"} {
		keyID := strings.Repeat(string(rune('a'+i)), 32)
		publicKey := strings.Repeat(string(rune('d'+i)), 64)
		content.WriteString(name + " " + name + "@example.org " + keyID + " 4:0.2c E 2025-01-01 2099-12-31\n\n")
		content.WriteString("-----Begin Mix Key-----\n" + keyID + "\n" + publicKey + "\n-----End Mix Key-----\n")
	}
	if err := os.WriteFile(path, []byte(content.String()), 0600); err != nil {
		t.Fatal(err)
	}
	return path
}

func TestValidateEmail(t *testing.T) {
	r := Request{Kind: Email, PublicKeyring: "/tmp/pubring.mix", Entry: "entry", Chain: []string{"entry"}, To: "user@example.org", Body: "hello"}
	if err := Validate(r); err != nil {
		t.Fatal(err)
	}
}

func TestValidateRejectsPlainIncompleteRequest(t *testing.T) {
	r := Request{Kind: Email, PublicKeyring: "/tmp/pubring.mix", Entry: "entry", Chain: []string{"entry"}, To: "bad", Body: "hello"}
	if err := Validate(r); err == nil {
		t.Fatal("expected invalid recipient")
	}
}

func TestValidateUsenetRequiresGatewayRecipient(t *testing.T) {
	r := Request{Kind: Usenet, PublicKeyring: "/tmp/pubring.mix", Chain: []string{"entry"}, Newsgroup: "misc.test", Body: "hello"}
	if err := Validate(r); err == nil {
		t.Fatal("expected missing Usenet gateway recipient to be rejected")
	}
	r.To = "mail2news@example.org"
	if err := Validate(r); err != nil {
		t.Fatalf("expected valid Usenet request: %v", err)
	}
}

func TestComposeUsenetGatewayHeaders(t *testing.T) {
	plain, err := composeMessage(Request{
		Kind: Usenet, To: "mail2news@example.org", Subject: "test", Newsgroup: "misc.test", Body: "hello",
	})
	if err != nil {
		t.Fatal(err)
	}
	text := string(plain)
	if !strings.Contains(text, "To: mail2news@example.org\n") || !strings.Contains(text, "Newsgroups: misc.test\n") {
		t.Fatalf("missing Usenet delivery headers: %q", text)
	}
}

func TestEncodeProducesYAMNArmor(t *testing.T) {
	keyring := testKeyring(t)
	result, err := Encode(Request{
		Kind: Email, PublicKeyring: keyring, Entry: "entry", Chain: []string{"entry"},
		From: "Anonymous <anon@example.org>", To: "user@example.org", Subject: "test", Body: "hello",
	})
	if err != nil {
		t.Fatal(err)
	}
	if result.EntryAddress != "entry@example.org" {
		t.Fatalf("unexpected entry address: %q", result.EntryAddress)
	}
	text := string(result.Envelope)
	if !strings.Contains(text, "-----BEGIN REMAILER MESSAGE-----") || !strings.Contains(text, "-----END REMAILER MESSAGE-----") {
		t.Fatal("missing YAMN armor markers")
	}
	lines := strings.Split(text, "\n")
	start := 0
	for i, line := range lines {
		if line == "-----BEGIN REMAILER MESSAGE-----" {
			start = i + 3
			break
		}
	}
	var encoded strings.Builder
	for _, line := range lines[start:] {
		if line == "" || strings.HasPrefix(line, "-----END") {
			break
		}
		encoded.WriteString(line)
	}
	packet, err := base64.StdEncoding.DecodeString(encoded.String())
	if err != nil {
		t.Fatal(err)
	}
	if len(packet) != messageBytes {
		t.Fatalf("unexpected packet size: got %d, want %d", len(packet), messageBytes)
	}
}

func TestEncodeMultiHop(t *testing.T) {
	result, err := Encode(Request{
		Kind: Email, PublicKeyring: testKeyring(t), Entry: "entry",
		Chain: []string{"entry", "middle", "exit"}, To: "user@example.org", Body: "hello",
	})
	if err != nil {
		t.Fatal(err)
	}
	if len(result.Envelope) == 0 || result.EntryAddress != "entry@example.org" {
		t.Fatal("multi-hop envelope was not produced")
	}
}
