package docker

import (
	"fmt"
	"os"
	"testing"

	"github.com/schmitthub/clawker/internal/logger"
	"github.com/schmitthub/clawker/internal/term"
)

func TestResetVisualStateUnlocked_Terminal(t *testing.T) {
	// Create a pipe to capture stdout output
	r, w, err := os.Pipe()
	if err != nil {
		t.Fatalf("failed to create pipe: %v", err)
	}
	defer r.Close()
	defer w.Close()

	// Create PTYHandler with pipe as stdout
	// We need a RawMode that reports IsTerminal() = true
	// Since RawMode.IsTerminal() checks term.IsTerminal(fd), we use the write end
	// of the pipe which won't be a terminal, but we can work around this by
	// testing the Restore method behavior instead.

	// For this test, we verify that when stdout IS writable, the sequence is written.
	// Create a handler with a custom fd that simulates terminal behavior.
	handler := &PTYHandler{
		stdin:   os.Stdin,
		stdout:  w,
		stderr:  os.Stderr,
		log:     logger.Nop(),
		rawMode: term.NewRawMode(int(w.Fd())),
	}

	// Since the pipe fd is not a real terminal, IsTerminal() will return false.
	// To properly test the write behavior, we need to mock the terminal check.
	// This test verifies that when IsTerminal returns false, nothing is written.
	handler.resetVisualStateUnlocked()

	// Close write end to allow read to complete
	w.Close()

	// Read any output
	buf := make([]byte, 256)
	n, _ := r.Read(buf)

	// Since IsTerminal() returns false for pipes, no output should be written
	if n != 0 {
		t.Errorf("expected no output for non-terminal, got %d bytes: %q", n, buf[:n])
	}
}

func TestResetVisualStateUnlocked_NonTerminal(t *testing.T) {
	// Create a pipe to capture stdout output
	r, w, err := os.Pipe()
	if err != nil {
		t.Fatalf("failed to create pipe: %v", err)
	}
	defer r.Close()

	handler := &PTYHandler{
		stdin:   os.Stdin,
		stdout:  w,
		stderr:  os.Stderr,
		log:     logger.Nop(),
		rawMode: term.NewRawMode(int(w.Fd())), // pipe is not a terminal
	}

	// Call resetVisualStateUnlocked - should be no-op for non-terminal
	handler.resetVisualStateUnlocked()

	// Close write end to allow read to complete
	w.Close()

	// Read any output
	buf := make([]byte, 256)
	n, _ := r.Read(buf)

	// Verify no output was written
	if n != 0 {
		t.Errorf("expected no output for non-terminal, got %d bytes: %q", n, buf[:n])
	}
}

func TestRestore_ResetsVisualState(t *testing.T) {
	// Create a pipe to capture stdout output
	r, w, err := os.Pipe()
	if err != nil {
		t.Fatalf("failed to create pipe: %v", err)
	}
	defer r.Close()

	handler := &PTYHandler{
		stdin:   os.Stdin,
		stdout:  w,
		stderr:  os.Stderr,
		log:     logger.Nop(),
		rawMode: term.NewRawMode(int(w.Fd())), // pipe is not a terminal
	}

	// Call Restore - should attempt to reset visual state then restore termios
	err = handler.Restore()
	if err != nil {
		t.Errorf("Restore() returned error: %v", err)
	}

	// Close write end to allow read to complete
	w.Close()

	// Read any output
	buf := make([]byte, 256)
	n, _ := r.Read(buf)

	// Since IsTerminal() returns false for pipes, no reset sequence should be written
	if n != 0 {
		t.Errorf("expected no reset output for non-terminal, got %d bytes: %q", n, buf[:n])
	}
}

func TestRestore_NoErrorOnNonTerminal(t *testing.T) {
	// Create a handler with non-terminal stdout
	handler := &PTYHandler{
		stdin:   os.Stdin,
		stdout:  os.Stdout,
		stderr:  os.Stderr,
		log:     logger.Nop(),
		rawMode: term.NewRawMode(-1), // invalid fd, but IsTerminal will return false
	}

	// Restore should succeed (no-op) for non-terminal
	err := handler.Restore()
	if err != nil {
		t.Errorf("Restore() should not error for non-terminal, got: %v", err)
	}
}

func TestIsClosedConnectionError(t *testing.T) {
	tests := []struct {
		name     string
		err      error
		expected bool
	}{
		{
			name:     "nil error",
			err:      nil,
			expected: false,
		},
		{
			name:     "closed connection error",
			err:      fmt.Errorf("read unix ->/var/run/docker.sock: use of closed network connection"),
			expected: true,
		},
		{
			name:     "wrapped closed connection error",
			err:      fmt.Errorf("copy failed: %w", fmt.Errorf("use of closed network connection")),
			expected: true,
		},
		{
			name:     "unrelated error",
			err:      fmt.Errorf("connection refused"),
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := isClosedConnectionError(tt.err)
			if got != tt.expected {
				t.Errorf("isClosedConnectionError(%v) = %v, want %v", tt.err, got, tt.expected)
			}
		})
	}
}
