"""
Tests for engine.terminal module.
"""

import io
import sys
from unittest.mock import patch

from engine import terminal


class TestTerminalDimensions:
    """Tests for terminal width/height functions."""

    def test_tw_returns_columns(self):
        """tw() returns terminal width."""
        with (
            patch.object(sys.stdout, "isatty", return_value=True),
            patch("os.get_terminal_size") as mock_size,
        ):
            mock_size.return_value = io.StringIO("columns=120")
            mock_size.columns = 120
            result = terminal.tw()
            assert isinstance(result, int)

    def test_th_returns_lines(self):
        """th() returns terminal height."""
        with (
            patch.object(sys.stdout, "isatty", return_value=True),
            patch("os.get_terminal_size") as mock_size,
        ):
            mock_size.return_value = io.StringIO("lines=30")
            mock_size.lines = 30
            result = terminal.th()
            assert isinstance(result, int)

    def test_tw_fallback_on_error(self):
        """tw() falls back to 80 on error."""
        with patch("os.get_terminal_size", side_effect=OSError):
            result = terminal.tw()
            assert result == 80

    def test_th_fallback_on_error(self):
        """th() falls back to 24 on error."""
        with patch("os.get_terminal_size", side_effect=OSError):
            result = terminal.th()
            assert result == 24


class TestANSICodes:
    """Tests for ANSI escape code constants."""

    def test_ansi_constants_exist(self):
        """All ANSI constants are defined."""
        assert terminal.RST == "\033[0m"
        assert terminal.BOLD == "\033[1m"
        assert terminal.DIM == "\033[2m"

    def test_green_shades_defined(self):
        """Green gradient colors are defined."""
        assert terminal.G_HI == "\033[38;5;46m"
        assert terminal.G_MID == "\033[38;5;34m"
        assert terminal.G_LO == "\033[38;5;22m"

    def test_white_shades_defined(self):
        """White/gray tones are defined."""
        assert terminal.W_COOL == "\033[38;5;250m"
        assert terminal.W_DIM == "\033[2;38;5;245m"

    def test_cursor_controls_defined(self):
        """Cursor control codes are defined."""
        assert "?" in terminal.CURSOR_OFF
        assert "?" in terminal.CURSOR_ON


class TestTypeOut:
    """Tests for type_out function."""

    @patch("sys.stdout", new_callable=io.StringIO)
    @patch("time.sleep")
    def test_type_out_writes_text(self, mock_sleep, mock_stdout):
        """type_out writes text to stdout."""
        with patch("random.random", return_value=0.5):
            terminal.type_out("Hi", color=terminal.G_HI)
            output = mock_stdout.getvalue()
            assert len(output) > 0

    @patch("time.sleep")
    def test_type_out_uses_color(self, mock_sleep):
        """type_out applies color codes."""
        with (
            patch("sys.stdout", new_callable=io.StringIO),
            patch("random.random", return_value=0.5),
        ):
            terminal.type_out("Test", color=terminal.G_HI)


class TestSlowPrint:
    """Tests for slow_print function."""

    @patch("sys.stdout", new_callable=io.StringIO)
    @patch("time.sleep")
    def test_slow_print_writes_text(self, mock_sleep, mock_stdout):
        """slow_print writes text to stdout."""
        terminal.slow_print("Hi", color=terminal.G_DIM, delay=0)
        output = mock_stdout.getvalue()
        assert len(output) > 0


class TestBootLn:
    """Tests for boot_ln function."""

    @patch("sys.stdout", new_callable=io.StringIO)
    @patch("time.sleep")
    def test_boot_ln_writes_label_and_status(self, mock_sleep, mock_stdout):
        """boot_ln shows label and status."""
        with patch("random.uniform", return_value=0):
            terminal.boot_ln("Loading", "OK", ok=True)
            output = mock_stdout.getvalue()
            assert "Loading" in output
            assert "OK" in output

    @patch("sys.stdout", new_callable=io.StringIO)
    @patch("time.sleep")
    def test_boot_ln_error_status(self, mock_sleep, mock_stdout):
        """boot_ln shows red for error status."""
        with patch("random.uniform", return_value=0):
            terminal.boot_ln("Loading", "FAIL", ok=False)
            output = mock_stdout.getvalue()
            assert "FAIL" in output
