"""Tests for prodigy_teams.ui — table helpers, formatting, silent mode, isatty."""

from __future__ import annotations

import io
import os
from enum import Enum
from unittest.mock import patch
from uuid import uuid4

from pydantic import BaseModel

from prodigy_teams.ui import (
    dicts_to_table,
    is_silent,
    isatty,
    print_args_table,
    print_as_json,
    print_info_table,
    print_logs,
    print_mutation_result,
    print_table_with_select,
)


class TestIsSilent:
    def test_not_silent_by_default(self):
        with patch.dict(os.environ, {}, clear=True):
            # Remove the key if present
            os.environ.pop("PRODIGY_TEAMS_CLI_SILENT", None)
            assert is_silent() is False

    def test_silent_when_env_set(self):
        with patch.dict(os.environ, {"PRODIGY_TEAMS_CLI_SILENT": "1"}):
            assert is_silent() is True


class TestIsatty:
    def test_stringio_not_tty(self):
        assert isatty(io.StringIO()) is False

    def test_no_isatty_method(self):
        assert isatty(object()) is False  # type: ignore[arg-type]


class TestDictsToTable:
    def test_empty_data(self):
        headers, rows = dicts_to_table([])
        assert headers == []
        assert rows == []

    def test_basic(self):
        data = [{"name": "a", "value": 1}, {"name": "b", "value": 2}]
        headers, rows = dicts_to_table(data)
        assert headers == ["name", "value"]
        assert rows == [["a", "1"], ["b", "2"]]

    def test_custom_headers(self):
        data = [{"name": "a", "value": 1, "extra": "x"}]
        headers, rows = dicts_to_table(data, headers=["name", "value"])
        assert headers == ["name", "value"]
        assert rows == [["a", "1"]]

    def test_missing_key(self):
        data = [{"name": "a"}]
        headers, rows = dicts_to_table(data, headers=["name", "missing"])
        assert rows == [["a", "None"]]

    def test_enum_value(self):
        class Color(Enum):
            RED = "red"

        data = [{"color": Color.RED}]
        headers, rows = dicts_to_table(data)
        assert rows == [["red"]]

    def test_exclude_dicts(self):
        data = [{"name": "a", "nested": {"key": "val"}}]
        headers, rows = dicts_to_table(data, exclude_dicts=True)
        # exclude_dicts filters dict values from items, but headers still
        # come from all keys.  The filtered item won't have "nested", so
        # item.get("nested", None) → "None" string.
        assert headers == ["name", "nested"]
        assert rows == [["a", "None"]]


class TestPrintAsJson:
    def test_prints_json(self, capsys):
        print_as_json({"key": "value"})
        captured = capsys.readouterr()
        assert '"key": "value"' in captured.out

    def test_silent_mode_suppresses(self, capsys):
        with patch.dict(os.environ, {"PRODIGY_TEAMS_CLI_SILENT": "1"}):
            print_as_json({"key": "value"})
        captured = capsys.readouterr()
        assert captured.out == ""


class TestPrintLogs:
    def test_prints_text(self, capsys):
        print_logs("some log text")
        captured = capsys.readouterr()
        assert "some log text" in captured.out

    def test_prints_json(self, capsys):
        print_logs("log text", as_json=True)
        captured = capsys.readouterr()
        assert '"logs"' in captured.out

    def test_none_text(self, capsys):
        print_logs(None)
        captured = capsys.readouterr()
        assert captured.out == ""

    def test_silent_suppresses(self, capsys):
        with patch.dict(os.environ, {"PRODIGY_TEAMS_CLI_SILENT": "1"}):
            print_logs("text")
        captured = capsys.readouterr()
        assert captured.out == ""


class TestPrintMutationResult:
    def test_prints_message(self, capsys):
        print_mutation_result({"ok": True}, "Done!", "detail")
        captured = capsys.readouterr()
        assert "Done!" in captured.out

    def test_as_json(self, capsys):
        print_mutation_result({"ok": True}, "Done!", as_json=True)
        captured = capsys.readouterr()
        assert '"ok": true' in captured.out

    def test_silent_suppresses(self, capsys):
        with patch.dict(os.environ, {"PRODIGY_TEAMS_CLI_SILENT": "1"}):
            print_mutation_result({"ok": True}, "Done!")
        captured = capsys.readouterr()
        assert captured.out == ""


class _SampleModel(BaseModel):
    name: str
    age: int


class TestPrintInfoTable:
    def test_prints_table(self, capsys):
        item = _SampleModel(name="Alice", age=30)
        print_info_table(item)
        captured = capsys.readouterr()
        assert "Alice" in captured.out

    def test_as_json(self, capsys):
        item = _SampleModel(name="Alice", age=30)
        print_info_table(item, as_json=True)
        captured = capsys.readouterr()
        assert '"name": "Alice"' in captured.out

    def test_select(self, capsys):
        item = _SampleModel(name="Alice", age=30)
        print_info_table(item, select=["name"])
        captured = capsys.readouterr()
        assert "Alice" in captured.out

    def test_exclude(self, capsys):
        item = _SampleModel(name="Alice", age=30)
        print_info_table(item, exclude=["age"], as_json=True)
        captured = capsys.readouterr()
        assert "age" not in captured.out

    def test_silent_suppresses(self, capsys):
        with patch.dict(os.environ, {"PRODIGY_TEAMS_CLI_SILENT": "1"}):
            print_info_table(_SampleModel(name="Alice", age=30))
        captured = capsys.readouterr()
        assert captured.out == ""


class TestPrintTableWithSelect:
    def test_basic(self, capsys):
        items = [_SampleModel(name="Alice", age=30)]
        print_table_with_select(items)
        captured = capsys.readouterr()
        assert "Alice" in captured.out

    def test_with_select(self, capsys):
        items = [_SampleModel(name="Alice", age=30)]
        print_table_with_select(items, select=["name"])
        captured = capsys.readouterr()
        assert "Alice" in captured.out

    def test_as_json(self, capsys):
        items = [_SampleModel(name="Alice", age=30)]
        print_table_with_select(items, as_json=True)
        captured = capsys.readouterr()
        assert '"name": "Alice"' in captured.out

    def test_silent_suppresses(self, capsys):
        with patch.dict(os.environ, {"PRODIGY_TEAMS_CLI_SILENT": "1"}):
            print_table_with_select([_SampleModel(name="Alice", age=30)])
        captured = capsys.readouterr()
        assert captured.out == ""

    def test_empty_list(self, capsys):
        print_table_with_select([])
        capsys.readouterr()
        # Should not crash


class TestPrintArgsTable:
    def test_basic(self, capsys):
        print_args_table({"model": "en_core_web_sm", "label": "ORG"})
        captured = capsys.readouterr()
        assert "en_core_web_sm" in captured.out

    def test_with_cli_names(self, capsys):
        print_args_table(
            {"model_name": "en_core_web_sm"},
            cli_names={"model": "model_name"},
        )
        captured = capsys.readouterr()
        assert "en_core_web_sm" in captured.out

    def test_uuid_value(self, capsys):
        uid = uuid4()
        print_args_table({"id": uid})
        captured = capsys.readouterr()
        assert str(uid) in captured.out

    def test_silent_suppresses(self, capsys):
        with patch.dict(os.environ, {"PRODIGY_TEAMS_CLI_SILENT": "1"}):
            print_args_table({"key": "val"})
        captured = capsys.readouterr()
        assert captured.out == ""
