"""
Feature: lr-qrm operator workflows
  Scenario: Check service status
    Given an authenticated engineer
    When they call `qrm status`
    Then they see the service health response.
"""

from __future__ import annotations

import importlib
import json
from importlib import metadata as importlib_metadata
from importlib.metadata import PackageNotFoundError
from datetime import datetime, timezone
from pathlib import Path

from typer.testing import CliRunner

from qrm import __version__
from qrm import cli
from qrm.client import LoginState

runner = CliRunner()


def test_status_command_calls_api(monkeypatch, tmp_path: Path) -> None:
    """Status should load stored credentials and print the API response."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )

    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    captured = {}

    class FakeClient:
        def __init__(self, base_url: str, verify_tls: bool) -> None:  # noqa: D401
            captured["base_url"] = base_url
            captured["verify_tls"] = verify_tls

        def status(self, token: str | None = None):  # noqa: D401
            captured["token"] = token
            return {"healthy": True}

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        ["status", "--config-path", str(config_path)],
    )

    assert result.exit_code == 0
    assert "healthy" in result.stdout
    assert "True" in result.stdout
    assert captured["token"] == "TOKEN123"
    assert captured["base_url"] == "https://qrm.local/api"
    assert captured["verify_tls"] is True


def test_status_command_supports_json_output(monkeypatch, tmp_path: Path) -> None:
    """Status should emit raw JSON when requested."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def status(self, token: str | None = None):  # noqa: D401
            return {"healthy": True, "token": token}

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        ["status", "--config-path", str(config_path), "--output", "json"],
    )

    assert result.exit_code == 0
    assert json.loads(result.stdout) == {"healthy": True, "token": "TOKEN123"}


def test_status_fails_when_config_missing(tmp_path: Path) -> None:
    """Status should exit with code 1 when config file is missing."""

    missing_path = tmp_path / "nope.json"

    result = runner.invoke(cli.app, ["status", "--config-path", str(missing_path)])

    assert result.exit_code == 1
    assert "No login state found" in result.stdout


def test_status_surfaces_client_error(monkeypatch, tmp_path: Path) -> None:
    """Status should surface QrmClientError nicely."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class ExplodingClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401
            pass

        def status(self, *_: str, **__: str):
            raise cli.QrmClientError("kaboom")

    monkeypatch.setattr(cli, "QrmClient", ExplodingClient)

    result = runner.invoke(
        cli.app,
        ["status", "--config-path", str(config_path)],
    )

    assert result.exit_code == 1
    assert "Status check failed" in result.stdout


def test_status_renders_list_payload(monkeypatch, tmp_path: Path) -> None:
    """Non-dict payloads should still print via console."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401
            pass

        def status(self, token: str | None = None):
            return ["ok", token]

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        ["status", "--config-path", str(config_path)],
    )

    assert result.exit_code == 0
    assert "ok" in result.stdout


def test_uut_status_command_calls_client(monkeypatch, tmp_path: Path) -> None:
    """The uut status subcommand should call the API and render a table."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    captured = {}

    class FakeClient:
        def __init__(self, base_url: str, verify_tls: bool) -> None:  # noqa: D401
            captured["base_url"] = base_url
            captured["verify_tls"] = verify_tls

        def uut_status(
            self,
            *,
            token: str,
            serial_number: str,
            start_datetime: str | None,
            stop_datetime: str | None,
            max_results: int | None,
        ):
            captured["token"] = token
            captured["serial_number"] = serial_number
            captured["start"] = start_datetime
            captured["stop"] = stop_datetime
            captured["max_results"] = max_results
            return [
                {
                    "ResultSetName": "Run #1",
                    "Outcome": "Passed",
                    "StartDateTime": "2026-02-06T07:08:59.863Z",
                    "StopDateTime": "2026-02-06T07:10:57.220Z",
                    "Info": {
                        "UutSerialNumber": "326115020010F2F1",
                        "StationName": "RYW1104",
                        "Operator": "Operator",
                    },
                }
            ]

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "uut",
            "status",
            "326115020010F2F1",
            "--start",
            "2026-02-01 00:00:00",
            "--stop",
            "2026-02-06 23:59:00",
            "--max-results",
            "50",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert "Run #1" in result.stdout
    assert "RYW1104" in result.stdout
    assert captured == {
        "base_url": "https://qrm.local/api",
        "verify_tls": True,
        "token": "TOKEN123",
        "serial_number": "326115020010F2F1",
        "start": "2026-02-01T00:00:00Z",
        "stop": "2026-02-06T23:59:00Z",
        "max_results": 50,
    }


def test_uut_status_command_supports_json_output(monkeypatch, tmp_path: Path) -> None:
    """JSON output should bypass table rendering."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def uut_status(self, **kwargs):  # noqa: ANN003
            return [{"serialNumber": kwargs["serial_number"], "Outcome": "Passed"}]

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "uut",
            "status",
            "326115020010F2F1",
            "--config-path",
            str(config_path),
            "--output",
            "json",
        ],
    )

    assert result.exit_code == 0
    assert json.loads(result.stdout) == [
        {"serialNumber": "326115020010F2F1", "Outcome": "Passed"}
    ]


def test_uut_status_defaults_time_window(monkeypatch, tmp_path: Path) -> None:
    """Start defaults to the epoch while stop defaults to the provided value."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    fake_start = datetime(1970, 1, 1, 0, 0, tzinfo=timezone.utc)
    fake_stop = None

    def fake_resolver(start, stop):  # noqa: ANN001
        assert start is None and stop is None
        return fake_start, fake_stop

    monkeypatch.setattr(cli, "_resolve_uut_window", fake_resolver)

    captured = {}

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def uut_status(self, **kwargs):  # noqa: ANN003
            captured["start"] = kwargs["start_datetime"]
            captured["stop"] = kwargs["stop_datetime"]
            return []

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "uut",
            "status",
            "ABC123",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert captured == {
        "start": "1970-01-01T00:00:00Z",
        "stop": None,
    }


def test_resolve_uut_window_defaults_epoch() -> None:
    """When only stop is provided, start should fall back to the epoch."""

    stop = datetime(2026, 2, 6, 0, 0, tzinfo=timezone.utc)

    start, resolved_stop = cli._resolve_uut_window(None, stop)

    assert start == datetime(1970, 1, 1, 0, 0, tzinfo=timezone.utc)
    assert resolved_stop == stop


def test_uut_status_handles_empty_payload(monkeypatch, tmp_path: Path) -> None:
    """An empty list should render the placeholder row."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def uut_status(self, **__: str):  # noqa: ANN003
            return []

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "uut",
            "status",
            "326115020010F2F1",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert "No results" in result.stdout


def test_uut_status_handles_irregular_rows(monkeypatch, tmp_path: Path) -> None:
    """Mixed payload elements should still render without crashing."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def uut_status(self, **__: str):  # noqa: ANN003
            return [
                {
                    "Id": 99,
                    "serialNumber": "ABC123",
                    "Outcome": "Failed",
                    "StartDateTime": datetime(2026, 2, 1, 12, 0, 0, tzinfo=timezone.utc),
                    "StopDateTime": 12345,
                    "Info": "oops",
                },
                "raw-string",
            ]

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "uut",
            "status",
            "ABC123",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert "Failed" in result.stdout
    assert "raw-string" in result.stdout
    assert "12345" in result.stdout


def test_box_list_command_calls_client(monkeypatch, tmp_path: Path) -> None:
    """The box list subcommand should call its API helper."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    captured = {}

    class FakeClient:
        def __init__(self, base_url: str, verify_tls: bool) -> None:  # noqa: D401
            captured["base_url"] = base_url
            captured["verify_tls"] = verify_tls

        def box_list(
            self,
            *,
            token: str,
            start_datetime: str | None,
            stop_datetime: str | None,
        ):
            captured["token"] = token
            captured["start"] = start_datetime
            captured["stop"] = stop_datetime
            return [
                {
                    "BoxId": "BOX-1",
                    "BoxName": "Fixture A",
                    "Status": "Active",
                    "StartDateTime": "2026-02-01T00:00:00Z",
                    "StopDateTime": "2026-02-02T00:00:00Z",
                    "Location": "OrbitOne",
                }
            ]

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "box",
            "list",
            "--start",
            "2026-02-01 00:00:00",
            "--stop",
            "2026-02-06 23:59:00",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert "Fixture A" in result.stdout
    assert captured == {
        "base_url": "https://qrm.local/api",
        "verify_tls": True,
        "token": "TOKEN123",
        "start": "2026-02-01T00:00:00Z",
        "stop": "2026-02-06T23:59:00Z",
    }


def test_box_list_command_supports_json_output(monkeypatch, tmp_path: Path) -> None:
    """Box list should honor --output json."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def box_list(self, **__: str):  # noqa: ANN003
            return [{"BoxId": "BOX-1"}]

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "box",
            "list",
            "--config-path",
            str(config_path),
            "--output",
            "json",
        ],
    )

    assert result.exit_code == 0
    assert json.loads(result.stdout) == [{"BoxId": "BOX-1"}]


def test_box_list_defaults_time_window(monkeypatch, tmp_path: Path) -> None:
    """Box list should default start to the epoch."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    fake_start = datetime(1970, 1, 1, 0, 0, tzinfo=timezone.utc)
    fake_stop = None

    def fake_resolver(start, stop):  # noqa: ANN001
        assert start is None and stop is None
        return fake_start, fake_stop

    monkeypatch.setattr(cli, "_resolve_box_window", fake_resolver)

    captured = {}

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def box_list(self, **kwargs):  # noqa: ANN003
            captured["start"] = kwargs["start_datetime"]
            captured["stop"] = kwargs["stop_datetime"]
            return []

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "box",
            "list",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert captured == {
        "start": "1970-01-01T00:00:00Z",
        "stop": None,
    }


def test_resolve_box_window_defaults_epoch() -> None:
    """Helper should mirror the epoch default behavior."""

    stop = datetime(2026, 2, 6, 0, 0, tzinfo=timezone.utc)

    start, resolved_stop = cli._resolve_box_window(None, stop)

    assert start == datetime(1970, 1, 1, 0, 0, tzinfo=timezone.utc)
    assert resolved_stop == stop


def test_box_list_handles_empty_payload(monkeypatch, tmp_path: Path) -> None:
    """Empty responses should render a helpful message."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def box_list(self, **__: str):  # noqa: ANN003
            return []

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "box",
            "list",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert "No results" in result.stdout


def test_box_list_handles_irregular_rows(monkeypatch, tmp_path: Path) -> None:
    """Irregular list entries should still render."""

    state = LoginState(  # type: ignore[call-arg]
        token="TOKEN123",
        username="alice",
        base_url="https://qrm.local/api",
        verify_tls=True,
    )
    config_path = tmp_path / "login.json"
    config_path.write_text(state.model_dump_json())

    class FakeClient:
        def __init__(self, *_: str, **__: str) -> None:  # noqa: D401, ANN001, ANN002, ANN003
            pass

        def box_list(self, **__: str):  # noqa: ANN003
            return [
                {
                    "Id": "BOX-1",
                    "Location": "OrbitOne",
                    "StartDateTime": datetime(2026, 2, 1, 12, 0, tzinfo=timezone.utc),
                    "StopDateTime": None,
                    "Status": "Active",
                },
                123,
            ]

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    result = runner.invoke(
        cli.app,
        [
            "box",
            "list",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    assert "BOX-1" in result.stdout
    assert "123" in result.stdout


def test_cli_displays_help_when_no_command() -> None:
    """Invoking the CLI without arguments returns the Typer help text."""

    result = runner.invoke(cli.app, [])

    assert result.exit_code == 0
    assert "Usage" in result.stdout


def test_version_option_returns_package_version() -> None:
    """`qrm --version` surfaces the packaged version string."""

    result = runner.invoke(cli.app, ["--version"])

    assert result.exit_code == 0
    assert __version__ in result.stdout


def test_version_fallback_reads_pyproject(monkeypatch) -> None:
    """If the package metadata is unavailable, fallback parser should work."""

    def raise_not_found(*_, **__) -> str:  # noqa: ANN002, ANN003
        raise PackageNotFoundError

    monkeypatch.setattr(importlib_metadata, "version", raise_not_found)

    import qrm as qrm_module

    reloaded = importlib.reload(qrm_module)

    assert reloaded._load_version() == __version__


def test_login_command_persists_token(monkeypatch, tmp_path):
    """The login command stores the returned token to disk."""

    captured = {}

    class FakeClient:
        def __init__(self, base_url: str, verify_tls: bool) -> None:  # noqa: D401
            captured["base_url"] = base_url
            captured["verify_tls"] = verify_tls

        def login(self, username: str, password: str) -> str:  # noqa: D401
            captured["username"] = username
            captured["password"] = password
            return "TOKEN123"

    monkeypatch.setattr(cli, "QrmClient", FakeClient)

    config_path = tmp_path / "login.json"
    result = runner.invoke(
        cli.app,
        [
            "login",
            "--username",
            "alice",
            "--password",
            "wonderland",
            "--base-url",
            "https://qrm.local/api",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 0
    data = json.loads(config_path.read_text())
    assert data["token"] == "TOKEN123"
    assert data["username"] == "alice"
    assert data["base_url"] == "https://qrm.local/api"
    assert data["verify_tls"] is True
    assert captured["verify_tls"] is True


def test_login_command_handles_client_errors(monkeypatch, tmp_path):
    """Failures surface as a helpful error with exit code 1."""

    class ExplodingClient:
        def __init__(self, *_, **__):  # noqa: D401, ANN002, ANN003
            pass

        def login(self, *_: str, **__: str) -> str:  # noqa: ANN001, ANN002, ANN003
            raise cli.QrmClientError("boom")

    monkeypatch.setattr(cli, "QrmClient", ExplodingClient)

    config_path = tmp_path / "login.json"
    result = runner.invoke(
        cli.app,
        [
            "login",
            "--username",
            "alice",
            "--password",
            "wonderland",
            "--config-path",
            str(config_path),
        ],
    )

    assert result.exit_code == 1
    assert "Login failed" in result.stdout
    assert not config_path.exists()
