"""Tests for the shared CLI configuration module."""

from __future__ import annotations

import json
import tempfile
from pathlib import Path
from unittest.mock import patch

import httpx
import pytest

from torivers_sdk.cli.commands._config import (
    API_TIMEOUT_SECONDS,
    PRODUCTION_API_BASE_URL,
    extract_error_message,
    get_api_base_url,
    get_auth_token,
    get_auth_url,
    get_config_path,
    is_authenticated,
    read_config,
)

# =============================================================================
# get_api_base_url
# =============================================================================


class TestGetApiBaseUrl:
    def test_env_var_wins(self) -> None:
        with patch.dict(
            "os.environ",
            {"TORIVERS_API_URL": "https://app.s.torivers.com/api"},
            clear=True,
        ):
            assert get_api_base_url() == "https://app.s.torivers.com/api"

    def test_env_var_strips_trailing_slash(self) -> None:
        with patch.dict(
            "os.environ",
            {"TORIVERS_API_URL": "https://app.torivers.com/api/"},
            clear=True,
        ):
            assert get_api_base_url() == "https://app.torivers.com/api"

    def test_env_var_strips_whitespace(self) -> None:
        with patch.dict(
            "os.environ",
            {"TORIVERS_API_URL": "  https://app.torivers.com/api  "},
            clear=True,
        ):
            assert get_api_base_url() == "https://app.torivers.com/api"

    def test_blank_env_var_ignored(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with patch.dict("os.environ", {"TORIVERS_API_URL": "  "}, clear=True):
                    assert get_api_base_url() == PRODUCTION_API_BASE_URL

    def test_config_file_fallback(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(
                json.dumps({"api_base_url": "https://app.c.torivers.com/api"})
            )
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with patch.dict("os.environ", {}, clear=True):
                    assert get_api_base_url() == "https://app.c.torivers.com/api"

    def test_production_default(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with patch.dict("os.environ", {}, clear=True):
                    assert get_api_base_url() == PRODUCTION_API_BASE_URL

    def test_env_var_takes_priority_over_config(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(
                json.dumps({"api_base_url": "https://app.c.torivers.com/api"})
            )
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with patch.dict(
                    "os.environ",
                    {"TORIVERS_API_URL": "https://app.s.torivers.com/api"},
                    clear=True,
                ):
                    assert get_api_base_url() == "https://app.s.torivers.com/api"


# =============================================================================
# get_auth_url
# =============================================================================


class TestGetAuthUrl:
    def test_derived_from_production_default(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with patch.dict("os.environ", {}, clear=True):
                    assert get_auth_url() == "https://app.torivers.com/auth/cli"

    def test_derived_from_staging_api_url(self) -> None:
        with patch.dict(
            "os.environ",
            {"TORIVERS_API_URL": "https://app.s.torivers.com/api"},
            clear=True,
        ):
            assert get_auth_url() == "https://app.s.torivers.com/auth/cli"

    def test_derived_from_local_api_url(self) -> None:
        with patch.dict(
            "os.environ",
            {"TORIVERS_API_URL": "https://app.c.torivers.com/api"},
            clear=True,
        ):
            assert get_auth_url() == "https://app.c.torivers.com/auth/cli"

    def test_derived_from_config_api_url(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(
                json.dumps({"api_base_url": "https://app.s.torivers.com/api"})
            )
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with patch.dict("os.environ", {}, clear=True):
                    assert get_auth_url() == "https://app.s.torivers.com/auth/cli"

    def test_env_var_override(self) -> None:
        with patch.dict(
            "os.environ",
            {"TORIVERS_AUTH_URL": "https://custom.example.com/login"},
            clear=True,
        ):
            assert get_auth_url() == "https://custom.example.com/login"

    def test_auth_url_env_var_takes_priority_over_api_url(self) -> None:
        with patch.dict(
            "os.environ",
            {
                "TORIVERS_API_URL": "https://app.s.torivers.com/api",
                "TORIVERS_AUTH_URL": "https://custom.example.com/login",
            },
            clear=True,
        ):
            assert get_auth_url() == "https://custom.example.com/login"


# =============================================================================
# read_config
# =============================================================================


class TestReadConfig:
    def test_missing_file(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert read_config() == {}

    def test_corrupt_json(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text("{broken json")
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert read_config() == {}

    def test_valid_config(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(
                json.dumps({"auth_token": "tok", "api_base_url": "https://example.com"})
            )
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                cfg = read_config()
                assert cfg["auth_token"] == "tok"
                assert cfg["api_base_url"] == "https://example.com"

    def test_non_dict_json(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text('"just a string"')
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert read_config() == {}


# =============================================================================
# is_authenticated
# =============================================================================


class TestIsAuthenticated:
    def test_true_when_token_present(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(
                json.dumps({"auth_token": "some-token"})
            )
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert is_authenticated() is True

    def test_false_when_no_config(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert is_authenticated() is False

    def test_false_when_empty_token(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(json.dumps({"auth_token": ""}))
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert is_authenticated() is False

    def test_false_when_whitespace_only_token(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(json.dumps({"auth_token": "   "}))
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert is_authenticated() is False


# =============================================================================
# get_auth_token
# =============================================================================


class TestGetAuthToken:
    def test_returns_token(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(
                json.dumps({"auth_token": "my-token"})
            )
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert get_auth_token() == "my-token"

    def test_raises_when_missing(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with pytest.raises(RuntimeError, match="Not authenticated"):
                    get_auth_token()

    def test_raises_when_empty(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(json.dumps({"auth_token": "   "}))
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                with pytest.raises(RuntimeError, match="Not authenticated"):
                    get_auth_token()

    def test_strips_whitespace(self) -> None:
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / ".torivers"
            config_dir.mkdir()
            (config_dir / "config.json").write_text(
                json.dumps({"auth_token": "  tok  "})
            )
            with patch("pathlib.Path.home", return_value=Path(tmpdir)):
                assert get_auth_token() == "tok"


# =============================================================================
# extract_error_message
# =============================================================================


class TestExtractErrorMessage:
    def _make_response(self, status_code: int, body: str) -> httpx.Response:
        return httpx.Response(
            status_code=status_code,
            content=body.encode(),
            request=httpx.Request("GET", "https://example.com"),
        )

    def test_json_error_field(self) -> None:
        resp = self._make_response(400, '{"error": "bad request"}')
        assert extract_error_message(resp) == "bad request"

    def test_json_message_field(self) -> None:
        resp = self._make_response(400, '{"message": "something went wrong"}')
        assert extract_error_message(resp) == "something went wrong"

    def test_plain_text_fallback(self) -> None:
        resp = self._make_response(500, "Internal Server Error")
        assert extract_error_message(resp) == "Internal Server Error"

    def test_empty_body_fallback(self) -> None:
        resp = httpx.Response(
            status_code=502,
            content=b"",
            request=httpx.Request("GET", "https://example.com"),
        )
        assert extract_error_message(resp) == "HTTP 502"


# =============================================================================
# get_config_path
# =============================================================================


class TestGetConfigPath:
    def test_returns_expected_path(self) -> None:
        path = get_config_path()
        assert path.name == "config.json"
        assert path.parent.name == ".torivers"


# =============================================================================
# Constants
# =============================================================================


class TestConstants:
    def test_production_api_base_url(self) -> None:
        assert PRODUCTION_API_BASE_URL == "https://app.torivers.com/api"

    def test_api_timeout(self) -> None:
        assert API_TIMEOUT_SECONDS == 30.0
