package cmd

import (
	"os"
	"strings"
	"testing"
)

func TestRawRequestFormatsJSONOutput(t *testing.T) {
	t.Parallel()

	rawBody := `{"ok":true,"nested":{"n":1}}`
	client := &recordingClinicClient{responses: []clinicResponse{{body: []byte(rawBody)}}}
	ctx := &RuntimeContext{Client: client}

	var stdout strings.Builder
	if err := rawCommandHandler(ctx, []string{
		"request",
		"--method", "GET",
		"--path", "/clinic/api/v1/orgs",
	}, &stdout); err != nil {
		t.Fatalf("rawCommandHandler() error = %v", err)
	}

	got := stdout.String()
	if !strings.Contains(got, "\n  ") {
		t.Fatalf("stdout is not indented JSON:\n%s", got)
	}
	if !strings.HasSuffix(got, "\n") {
		t.Fatalf("stdout does not end with newline:\n%s", got)
	}
	assertJSONEqual(t, got, rawBody)
}

func TestWriteJSONDoesNotHTMLEscapeCharacters(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := writeJSON(&stdout, map[string]any{
		"text": "<tag>&value",
	}); err != nil {
		t.Fatalf("writeJSON() error = %v", err)
	}

	got := stdout.String()
	if strings.Contains(got, "\\u003c") || strings.Contains(got, "\\u003e") || strings.Contains(got, "\\u0026") {
		t.Fatalf("writeJSON output contains HTML escapes:\n%s", got)
	}
	if !strings.Contains(got, "<tag>&value") {
		t.Fatalf("writeJSON output missing expected literal text:\n%s", got)
	}
}

func TestFormatJSONForWriterAddsANSIWhenColorEnabled(t *testing.T) {
	t.Parallel()

	raw := []byte(`{"k":"v","n":1,"b":true,"z":null}`)
	got, err := formatJSONForWriter(raw, true)
	if err != nil {
		t.Fatalf("formatJSONForWriter() error = %v", err)
	}

	output := string(got)
	if !strings.Contains(output, "\x1b[") {
		t.Fatalf("expected ANSI color sequence in output:\n%s", output)
	}
	assertJSONEqual(t, stripANSICodes(output), string(raw))
}

func TestFormatJSONForWriterDisablesANSIWhenColorDisabled(t *testing.T) {
	t.Parallel()

	raw := []byte(`{"k":"v","n":1}`)
	got, err := formatJSONForWriter(raw, false)
	if err != nil {
		t.Fatalf("formatJSONForWriter() error = %v", err)
	}

	output := string(got)
	if strings.Contains(output, "\x1b[") {
		t.Fatalf("unexpected ANSI color sequence in output:\n%s", output)
	}
	assertJSONEqual(t, output, string(raw))
}

func TestShouldColorizeWriterFalseForPipeAndBuilder(t *testing.T) {
	t.Parallel()

	var builder strings.Builder
	if shouldColorizeWriter(&builder) {
		t.Fatal("shouldColorizeWriter(builder) = true, want false")
	}

	reader, writer, err := os.Pipe()
	if err != nil {
		t.Fatalf("os.Pipe() error = %v", err)
	}
	defer reader.Close()
	defer writer.Close()

	if shouldColorizeWriter(writer) {
		t.Fatal("shouldColorizeWriter(pipe writer) = true, want false")
	}
}

func stripANSICodes(value string) string {
	replacer := strings.NewReplacer(
		ansiReset, "",
		ansiNull, "",
		ansiBool, "",
		ansiNumber, "",
		ansiString, "",
		ansiObjectKey, "",
	)
	return replacer.Replace(value)
}
