package cli

import (
	"os"
	"syscall"
	"testing"
	"unsafe"
)

func TestIsTerminalFileNil(t *testing.T) {
	if IsTerminalFile(nil) {
		t.Fatal("expected nil file not to be a terminal")
	}
}

func TestIsTerminalFile(t *testing.T) {
	origIoctlFunc := ioctlFunc
	defer func() { ioctlFunc = origIoctlFunc }()

	tmp, err := os.CreateTemp("", "terminal_file_test")
	if err != nil {
		t.Fatalf("CreateTemp failed: %v", err)
	}
	defer os.Remove(tmp.Name())
	defer tmp.Close()

	ioctlFunc = func(fd, req uintptr, arg unsafe.Pointer) syscall.Errno {
		if fd != tmp.Fd() {
			t.Errorf("ioctl fd = %d, want %d", fd, tmp.Fd())
		}
		if req != uintptr(syscall.TCGETS) {
			t.Errorf("ioctl req = %d, want %d", req, syscall.TCGETS)
		}
		return 0
	}

	if !IsTerminalFile(tmp) {
		t.Fatal("expected file with successful terminal ioctl to be a terminal")
	}
}

func TestIsTerminalFileIoctlFailure(t *testing.T) {
	origIoctlFunc := ioctlFunc
	defer func() { ioctlFunc = origIoctlFunc }()

	tmp, err := os.CreateTemp("", "terminal_file_test")
	if err != nil {
		t.Fatalf("CreateTemp failed: %v", err)
	}
	defer os.Remove(tmp.Name())
	defer tmp.Close()

	ioctlFunc = func(_, _ uintptr, _ unsafe.Pointer) syscall.Errno { return syscall.ENOTTY }

	if IsTerminalFile(tmp) {
		t.Fatal("expected file with failing terminal ioctl not to be a terminal")
	}
}

func TestTerminalWidthNil(t *testing.T) {
	if got := TerminalWidth(nil); got != 0 {
		t.Fatalf("TerminalWidth(nil) = %d, want 0", got)
	}
}

func TestTerminalWidth(t *testing.T) {
	origIoctlFunc := ioctlFunc
	defer func() { ioctlFunc = origIoctlFunc }()

	tmp, err := os.CreateTemp("", "terminal_width_test")
	if err != nil {
		t.Fatalf("CreateTemp failed: %v", err)
	}
	defer os.Remove(tmp.Name())
	defer tmp.Close()

	ioctlFunc = func(fd, req uintptr, arg unsafe.Pointer) syscall.Errno {
		if fd != tmp.Fd() {
			t.Errorf("ioctl fd = %d, want %d", fd, tmp.Fd())
		}
		if req != uintptr(syscall.TIOCGWINSZ) {
			t.Errorf("ioctl req = %d, want %d", req, syscall.TIOCGWINSZ)
		}
		ws := (*struct {
			row, col       uint16
			xpixel, ypixel uint16
		})(arg)
		ws.col = 123
		return 0
	}

	if got := TerminalWidth(tmp); got != 123 {
		t.Fatalf("TerminalWidth() = %d, want 123", got)
	}
}

func TestTerminalWidthIoctlFailure(t *testing.T) {
	origIoctlFunc := ioctlFunc
	defer func() { ioctlFunc = origIoctlFunc }()

	tmp, err := os.CreateTemp("", "terminal_width_test")
	if err != nil {
		t.Fatalf("CreateTemp failed: %v", err)
	}
	defer os.Remove(tmp.Name())
	defer tmp.Close()

	ioctlFunc = func(_, _ uintptr, _ unsafe.Pointer) syscall.Errno { return syscall.ENOTTY }

	if got := TerminalWidth(tmp); got != 0 {
		t.Fatalf("TerminalWidth() = %d, want 0", got)
	}
}
