"""CLI-session lifecycle, scope, and workspace-race behavior."""

from __future__ import annotations

import json
from typing import TYPE_CHECKING, Any

import pytest
import requests
from rich.console import Console

from strix.interface import cloud, platform_cli, platform_identity
from strix.interface.cloud import http
from strix.interface.cloud import session as cloud_session


if TYPE_CHECKING:
    from pathlib import Path


class Response:
    def __init__(self, payload: Any = None, status_code: int = 200) -> None:
        self._payload = payload
        self.status_code = status_code
        self.ok = 200 <= status_code < 400
        self.text = json.dumps(payload) if payload is not None else ""
        self.headers = {"content-type": "application/json"}

    def json(self) -> Any:
        return self._payload


@pytest.fixture
def auth_path(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
    path = tmp_path / "platform-auth.json"
    monkeypatch.setattr(platform_cli, "AUTH_PATH", path)
    monkeypatch.delenv("STRIX_API_TOKEN", raising=False)
    monkeypatch.delenv("STRIX_WORKSPACE_ID", raising=False)
    return path


def test_http_workspace_pin_is_captured_once(
    auth_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    platform_cli.save_record(
        {
            "api_token": "secret",
            "organization_id": "org_start",
            "app_url": "https://app.example.test",
        }
    )
    assert auth_path.exists()
    sent: list[dict[str, str]] = []

    def fake_request(*_args: Any, **kwargs: Any) -> Response:
        sent.append(dict(kwargs["headers"]))
        return Response({})

    monkeypatch.setattr(requests, "request", fake_request)
    http.configure()
    platform_cli.save_record(
        {
            "api_token": "secret",
            "organization_id": "org_changed_elsewhere",
            "app_url": "https://app.example.test",
        }
    )
    http.request("GET", "/scans")
    assert sent[0]["X-Strix-Workspace"] == "org_start"


def test_session_scope_update_persists_only_for_stored_session(
    auth_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: Any
) -> None:
    platform_cli.save_record(
        {
            "api_token": "secret",
            "organization_id": "org_1",
            "app_url": "https://app.example.test",
            "scopes": ["scans:read"],
        }
    )
    monkeypatch.setattr(
        http,
        "request",
        lambda *_args, **_kwargs: Response(
            {
                "scopes": ["scans:read", "scans:write", "billing:read"],
                "requested_scopes": ["scans:read", "scans:write", "billing:read"],
                "scope_ceiling": ["scans:read", "scans:write", "billing:read"],
                "scope_profile": "minimal",
            }
        ),
    )
    assert cloud.run_cloud(["session", "scopes", "set", "minimal", "--json"]) == 0
    stored = platform_cli.read_record()
    assert stored is not None
    assert stored["scope_profile"] == "minimal"
    assert json.loads(capsys.readouterr().out)["scope_profile"] == "minimal"

    before = auth_path.read_text(encoding="utf-8")
    assert (
        cloud.run_cloud(["session", "scopes", "set", "minimal", "--token", "override", "--json"])
        == 0
    )
    assert auth_path.read_text(encoding="utf-8") == before


def test_logout_keeps_local_token_when_remote_outcome_is_not_definitive(
    auth_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: Any
) -> None:
    platform_cli.save_record(
        {
            "api_token": "secret",
            "organization_id": "org_1",
            "app_url": "https://app.example.test",
        }
    )
    monkeypatch.setattr(
        requests,
        "delete",
        lambda *_args, **_kwargs: Response({"detail": "unavailable"}, 503),
    )
    assert cloud.run_cloud(["logout", "--json"]) == 1
    assert auth_path.exists()
    assert json.loads(capsys.readouterr().out)["removed"] is False


def test_local_only_logout_is_explicit_and_recoverable(auth_path: Path, capsys: Any) -> None:
    platform_cli.save_record({"api_token": "secret"})
    assert cloud.run_cloud(["logout", "--local-only", "--json"]) == 0
    payload = json.loads(capsys.readouterr().out)
    assert payload["local_only"] is True
    assert payload["remotely_revoked"] is False
    assert not auth_path.exists()


def test_session_json_errors_preserve_machine_readable_server_details(capsys: Any) -> None:
    error = http.CloudError(
        "workspace changed",
        payload={
            "detail": "workspace changed",
            "code": "workspace_session_changed",
            "current_organization_id": "org_current",
        },
    )

    assert cloud_session._error(Console(), error, as_json=True) == http.EXIT_ERROR
    payload = json.loads(capsys.readouterr().out)
    assert payload == {
        "code": "workspace_session_changed",
        "current_organization_id": "org_current",
        "error": "workspace changed",
    }


def test_cli_device_identity_is_stable_and_privacy_safe(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    path = tmp_path / "cli-identity.json"
    monkeypatch.setattr(platform_identity, "IDENTITY_PATH", path)
    first = platform_identity.read_or_create_identity()
    second = platform_identity.read_or_create_identity(device_name="  Build   laptop  ")
    assert second["client_instance_id"] == first["client_instance_id"]
    assert second["device_name"] == "Build laptop"
    assert path.stat().st_mode & 0o777 == 0o600
