"""
Tests de autenticación del Agent CLI.
"""
import json
import os
import stat
import tempfile
from pathlib import Path
from unittest.mock import patch, MagicMock

import pytest

from jama_agent.auth import (
    clear_credentials,
    load_credentials,
    login,
    save_credentials,
)


@pytest.fixture
def temp_credentials(tmp_path):
    """Override del path de credenciales para tests."""
    creds_path = tmp_path / "credentials.json"
    with patch("jama_agent.auth.CREDENTIALS_PATH", creds_path):
        yield creds_path


class TestSaveCredentials:
    """Tests de save_credentials."""

    def test_creates_file(self, temp_credentials):
        """save_credentials crea el archivo."""
        save_credentials({"token": "abc"})
        assert temp_credentials.exists()

    def test_file_permissions(self, temp_credentials):
        """El archivo se crea con permisos 0o600."""
        save_credentials({"token": "abc"})
        mode = stat.S_IMODE(os.stat(temp_credentials).st_mode)
        assert mode == 0o600

    def test_content_is_valid_json(self, temp_credentials):
        """El contenido es JSON válido."""
        data = {"server": "http://test", "token": "xyz"}
        save_credentials(data)
        with open(temp_credentials) as f:
            loaded = json.load(f)
        assert loaded == data


class TestLoadCredentials:
    """Tests de load_credentials."""

    def test_returns_none_without_file(self, temp_credentials):
        """Sin archivo → retorna None."""
        result = load_credentials()
        assert result is None

    def test_reads_file(self, temp_credentials):
        """Lee el archivo correctamente."""
        data = {"server": "http://x", "token": "y"}
        save_credentials(data)
        result = load_credentials()
        assert result == data

    def test_returns_none_on_invalid_json(self, temp_credentials):
        """JSON inválido → retorna None."""
        temp_credentials.write_text("not json {{{")
        result = load_credentials()
        assert result is None


class TestClearCredentials:
    """Tests de clear_credentials."""

    def test_removes_file(self, temp_credentials):
        """clear_credentials elimina el archivo."""
        save_credentials({"x": 1})
        assert temp_credentials.exists()
        clear_credentials()
        assert not temp_credentials.exists()

    def test_no_error_if_missing(self, temp_credentials):
        """No falla si el archivo no existe."""
        clear_credentials()  # No debería lanzar excepción


class TestLogin:
    """Tests de la función login."""

    @patch("jama_agent.auth.save_credentials")
    @patch("jama_agent.auth.httpx.post")
    def test_successful_login(self, mock_post, mock_save):
        """Login exitoso guarda credenciales."""
        mock_response = MagicMock()
        mock_response.json.return_value = {
            "access_token": "tok-123",
            "refresh_token": "ref-456",
        }
        mock_response.raise_for_status = MagicMock()
        mock_post.return_value = mock_response

        result = login("http://server", "user@test.com", "pass")

        assert result["server"] == "http://server"
        assert result["email"] == "user@test.com"
        assert result["access_token"] == "tok-123"
        mock_save.assert_called_once()

    @patch("jama_agent.auth.httpx.post")
    def test_login_invalid_credentials(self, mock_post):
        """Credenciales inválidas → HTTPStatusError."""
        import httpx

        mock_response = MagicMock()
        mock_response.raise_for_status.side_effect = httpx.HTTPStatusError(
            "401", request=MagicMock(), response=MagicMock()
        )
        mock_post.return_value = mock_response

        with pytest.raises(httpx.HTTPStatusError):
            login("http://server", "bad@test.com", "wrong")

    @patch("jama_agent.auth.httpx.post")
    def test_login_connection_error(self, mock_post):
        """Servidor no disponible → ConnectError."""
        import httpx

        mock_post.side_effect = httpx.ConnectError("Connection refused")

        with pytest.raises(httpx.ConnectError):
            login("http://unreachable", "a@b.com", "pass")
