"""Tests for the CLI submit flow — Chutes auth status check and token storage."""

from __future__ import annotations

import argparse
import json
import sys
import types
from http import HTTPStatus
from types import SimpleNamespace
from unittest.mock import MagicMock, patch

import pytest

from oro_sdk.models.admission_status import AdmissionStatus
from oro_sdk.models.chutes_auth_status_response import ChutesAuthStatusResponse
from oro_sdk.models.submit_agent_response import SubmitAgentResponse
from oro_sdk.types import Response

# Stub bittensor_wallet so patch() works without the optional dependency.
if "bittensor_wallet" not in sys.modules:
    _bw = types.ModuleType("bittensor_wallet")
    _bw.Wallet = MagicMock  # type: ignore[attr-defined]
    sys.modules["bittensor_wallet"] = _bw

_OK_SUBMIT = Response(
    status_code=HTTPStatus.OK, content=b"{}", headers={},
    parsed=SubmitAgentResponse(
        admission_status=AdmissionStatus.ACCEPTED, hotkey="5Fake", message="OK",
    ),
)
_OK_STORE = Response(status_code=HTTPStatus.OK, content=b"{}", headers={}, parsed=None)
_ERR_STORE = Response(
    status_code=HTTPStatus.INTERNAL_SERVER_ERROR, headers={}, parsed=None,
    content=json.dumps({"detail": "storage failed"}).encode(),
)


@pytest.fixture()
def cli(tmp_path):
    """Patch all _submit dependencies with happy-path defaults. Returns (run, mocks).

    Call run() to invoke _submit. Override mocks.X.return_value before calling
    to test unhappy paths — only configure what the test cares about.
    """
    agent_file = tmp_path / "agent.py"
    agent_file.write_text("print('hello')")
    args = argparse.Namespace(
        agent_name="test-agent", agent_file=agent_file,
        wallet_name="default", wallet_hotkey="default",
        base_url="http://localhost:8000",
    )

    with (
        patch("bittensor_wallet.Wallet") as mock_wallet,
        patch("oro_sdk.bittensor_auth.BittensorAuthClient"),
        patch("oro_sdk.api.miner.get_chutes_auth_status.sync") as status,
        patch("oro_sdk.api.miner.store_chutes_token.sync_detailed") as store,
        patch("oro_sdk.api.miner.submit_agent.sync_detailed") as submit,
        patch("oro_sdk.chutes_auth.start_auth_flow") as auth_flow,
    ):
        w = MagicMock(); w.name = "default"; w.hotkey.ss58_address = "5Fake"
        mock_wallet.return_value = w

        # Happy-path defaults: token already stored, submission succeeds.
        status.return_value = ChutesAuthStatusResponse(connected=True)
        submit.return_value = _OK_SUBMIT

        from oro_sdk.cli import _submit
        m = SimpleNamespace(status=status, store=store, submit=submit,
                            auth_flow=auth_flow, args=args)
        yield lambda **kw: _submit(argparse.Namespace(**{**vars(args), **kw})), m


class TestChutesAuthFlow:
    def test_skips_auth_when_already_connected(self, cli, capsys):
        run, m = cli
        run()

        m.auth_flow.assert_not_called()
        m.store.assert_not_called()
        m.submit.assert_called_once()
        assert "already stored" in capsys.readouterr().out

    def test_runs_oauth_when_not_connected(self, cli):
        run, m = cli
        m.status.return_value = ChutesAuthStatusResponse(connected=False)
        m.auth_flow.return_value = {"refresh_token": "oauth-token"}
        m.store.return_value = _OK_STORE

        run()

        m.auth_flow.assert_called_once()
        assert m.store.call_args.kwargs["body"].refresh_token == "oauth-token"

    def test_exits_on_store_failure(self, cli):
        run, m = cli
        m.status.return_value = ChutesAuthStatusResponse(connected=False)
        m.auth_flow.return_value = {"refresh_token": "tok"}
        m.store.return_value = _ERR_STORE

        with pytest.raises(SystemExit, match="1"):
            run()
        m.submit.assert_not_called()

    def test_no_inline_token_in_submit_body(self, cli):
        run, m = cli
        run()

        body = m.submit.call_args.kwargs["body"]
        assert "chutes_refresh_token" not in body.additional_properties
