"""Tests for CSV output format, --no-headers, and --field-selector."""

from __future__ import annotations

from io import StringIO

from rich.console import Console

from ilum.cli.formatters import (
    CommandResult,
    OutputFormat,
    ResultFormatter,
    _apply_field_selector,
)
from ilum.cli.output import IlumConsole


def _capture_console() -> tuple[IlumConsole, StringIO]:
    """Create an IlumConsole that writes to a StringIO buffer."""
    buf = StringIO()
    console = IlumConsole()
    console._console = Console(file=buf, highlight=False, no_color=True)
    return console, buf


class TestOutputFormatEnum:
    def test_csv_member_exists(self) -> None:
        assert OutputFormat.CSV == "csv"

    def test_csv_from_string(self) -> None:
        assert OutputFormat("csv") == OutputFormat.CSV


class TestCommandResultColumns:
    def test_columns_default_none(self) -> None:
        r = CommandResult(data=[], summary="ok")
        assert r.columns is None

    def test_columns_set(self) -> None:
        r = CommandResult(data=[], summary="ok", columns=["a", "b"])
        assert r.columns == ["a", "b"]


class TestCSVFormatter:
    def test_list_of_dicts(self) -> None:
        console, buf = _capture_console()
        data = [{"name": "core", "status": "ok"}, {"name": "ui", "status": "warn"}]
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console)
        output = buf.getvalue()
        assert "name,status" in output
        assert "core,ok" in output
        assert "ui,warn" in output

    def test_list_of_dicts_no_headers(self) -> None:
        console, buf = _capture_console()
        data = [{"name": "core", "status": "ok"}]
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console, no_headers=True)
        output = buf.getvalue()
        assert "name,status" not in output
        assert "core,ok" in output

    def test_single_dict(self) -> None:
        console, buf = _capture_console()
        data = {"release": "ilum", "status": "deployed"}
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console)
        output = buf.getvalue()
        assert "release,status" in output
        assert "ilum,deployed" in output

    def test_single_dict_no_headers(self) -> None:
        console, buf = _capture_console()
        data = {"release": "ilum", "status": "deployed"}
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console, no_headers=True)
        output = buf.getvalue()
        assert "release,status" not in output
        assert "ilum,deployed" in output

    def test_empty_list(self) -> None:
        console, buf = _capture_console()
        result = CommandResult(data=[], summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console)
        output = buf.getvalue().strip()
        assert output == ""

    def test_flat_list(self) -> None:
        console, buf = _capture_console()
        data = ["core", "ui", "jupyter"]
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console)
        output = buf.getvalue()
        assert "value" in output
        assert "core" in output
        assert "jupyter" in output

    def test_flat_list_no_headers(self) -> None:
        console, buf = _capture_console()
        data = ["core", "ui"]
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console, no_headers=True)
        output = buf.getvalue()
        assert "value" not in output
        assert "core" in output

    def test_custom_columns(self) -> None:
        console, buf = _capture_console()
        data = [{"name": "core", "status": "ok", "extra": "x"}]
        result = CommandResult(data=data, summary="", columns=["name", "status"])
        ResultFormatter().format(result, OutputFormat.CSV, console)
        output = buf.getvalue()
        assert "name,status" in output
        # 'extra' should not appear as a header
        assert "extra" not in output.split("\n")[0]

    def test_csv_escaping(self) -> None:
        console, buf = _capture_console()
        data = [{"msg": 'value with "quotes"', "val": "has,comma"}]
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(result, OutputFormat.CSV, console)
        output = buf.getvalue()
        # CSV module should properly escape these
        assert '"' in output


class TestFieldSelector:
    def test_filter_list_of_dicts(self) -> None:
        data = [{"name": "core", "status": "ok", "version": "1.0"}]
        result = _apply_field_selector(data, ["name", "status"])
        assert result == [{"name": "core", "status": "ok"}]

    def test_filter_single_dict(self) -> None:
        data = {"name": "core", "status": "ok", "version": "1.0"}
        result = _apply_field_selector(data, ["name"])
        assert result == {"name": "core"}

    def test_missing_fields_ignored(self) -> None:
        data = [{"name": "core"}]
        result = _apply_field_selector(data, ["name", "nonexistent"])
        assert result == [{"name": "core"}]

    def test_field_selector_with_json_format(self) -> None:
        console, buf = _capture_console()
        data = [{"name": "core", "status": "ok", "extra": "x"}]
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(
            result, OutputFormat.JSON, console, field_selector=["name", "status"]
        )
        output = buf.getvalue()
        assert "core" in output
        assert "extra" not in output

    def test_field_selector_with_csv_format(self) -> None:
        console, buf = _capture_console()
        data = [{"name": "core", "status": "ok", "extra": "x"}]
        result = CommandResult(data=data, summary="")
        ResultFormatter().format(
            result, OutputFormat.CSV, console, field_selector=["name", "status"]
        )
        output = buf.getvalue()
        assert "core" in output
        assert "extra" not in output


class TestNoHeadersOnTable:
    def test_no_headers_flag_on_console(self) -> None:
        console = IlumConsole()
        assert console.no_headers is False
        console.no_headers = True
        assert console.no_headers is True

    def test_field_selector_on_console(self) -> None:
        console = IlumConsole()
        assert console.field_selector is None
        console.field_selector = ["name", "status"]
        assert console.field_selector == ["name", "status"]
