"""Tests for AppsResource."""

from __future__ import annotations

import httpx
import pytest

from appliku import Appliku


@pytest.fixture()
def app_data() -> dict[str, object]:
    return {
        "id": 42,
        "name": "web-app",
        "branch": "main",
        "status": "deployed",
        "build_pack": "dockerfile",
    }


@pytest.fixture()
def deployment_data() -> dict[str, object]:
    return {
        "id": 7,
        "app_id": 42,
        "app_name": "web-app",
        "status": "running",
        "is_active": True,
        "is_aborted": False,
    }


class TestAppsList:
    def test_list_returns_apps(
        self,
        mock_client: tuple[Appliku, list[httpx.Response]],
        app_data: dict[str, object],
    ) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json=[app_data]))
        result = client.apps.list("acme")
        assert len(result) == 1
        assert result[0].name == "web-app"


class TestAppsGet:
    def test_get_returns_app(
        self, mock_client: tuple[Appliku, list[httpx.Response]], app_data: dict[str, object]
    ) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json=app_data))
        app = client.apps.get("acme", 42)
        assert app.id == 42
        assert app.name == "web-app"


class TestAppsCreate:
    def test_create_returns_app(
        self, mock_client: tuple[Appliku, list[httpx.Response]], app_data: dict[str, object]
    ) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(201, json=app_data))
        app = client.apps.create("acme", name="web-app", branch="main")
        assert app.name == "web-app"
        assert app.id == 42


class TestAppsUpdate:
    def test_update_returns_app(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        updated = {"id": 42, "name": "renamed-app", "branch": "develop", "status": "deployed"}
        responses.append(httpx.Response(200, json=updated))
        app = client.apps.update("acme", 42, name="renamed-app", branch="develop")
        assert app.name == "renamed-app"


class TestAppsDelete:
    def test_delete_succeeds(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(204))
        client.apps.delete("acme", 42)


class TestAppsDeploy:
    def test_deploy_returns_deployment(
        self, mock_client: tuple[Appliku, list[httpx.Response]], deployment_data: dict[str, object]
    ) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json=deployment_data))
        dep = client.apps.deploy("acme", 42)
        assert dep.id == 7
        assert dep.status == "running"


class TestAppsConfigVars:
    def test_get_config_vars(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json={"vars": {"FOO": "bar", "BAZ": "qux"}}))
        vars_dict = client.apps.get_config_vars("acme", 42)
        assert vars_dict == {"FOO": "bar", "BAZ": "qux"}

    def test_set_config_vars(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json={"vars": {"NEW": "value"}}))
        result = client.apps.set_config_vars("acme", 42, {"NEW": "value"})
        assert result == {"NEW": "value"}


class TestAppsServiceLogs:
    def test_service_logs(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json={"id": 10, "logs": "2024-01-01 app started\n"}))
        result = client.apps.service_logs("acme", 42, "web", tail=50)
        assert result.id == 10
        assert "app started" in result.logs


class TestAppsLoadBalancerLogs:
    def test_load_balancer_logs(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json={"id": 11, "logs": "GET / 200\n"}))
        result = client.apps.load_balancer_logs("acme", 42, "example.com", tail=10)
        assert result.id == 11
        assert "GET" in result.logs


class TestAppsAppLogs:
    def test_app_logs_immediate(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        # Step 1: request returns request_id
        responses.append(httpx.Response(200, json={"request_id": 1234.5, "tail": 100}))
        # Step 2: retrieve returns logs immediately (status != pending)
        responses.append(
            httpx.Response(
                200,
                json={
                    "id": 20,
                    "logs": "app log line",
                    "request_id": 1234.5,
                    "status": "completed",
                },
            )
        )
        result = client.apps.app_logs("acme", 42, "worker")
        assert result.status == "completed"
        assert result.logs == "app log line"

    def test_app_logs_polls_until_ready(
        self, mock_client: tuple[Appliku, list[httpx.Response]], monkeypatch: pytest.MonkeyPatch
    ) -> None:
        monkeypatch.setattr("appliku.resources.apps.time.sleep", lambda _: None)
        client, responses = mock_client
        responses.append(httpx.Response(200, json={"request_id": 99.0, "tail": 100}))
        # Two pending, then completed
        responses.append(
            httpx.Response(
                200, json={"id": 21, "logs": None, "request_id": 99.0, "status": "pending"}
            )
        )
        responses.append(
            httpx.Response(
                200, json={"id": 22, "logs": None, "request_id": 99.0, "status": "pending"}
            )
        )
        responses.append(
            httpx.Response(
                200, json={"id": 23, "logs": "final", "request_id": 99.0, "status": "completed"}
            )
        )
        result = client.apps.app_logs("acme", 42, "worker")
        assert result.logs == "final"
        assert result.status == "completed"


class TestAppsNginxLogs:
    def test_nginx_logs_immediate(self, mock_client: tuple[Appliku, list[httpx.Response]]) -> None:
        client, responses = mock_client
        responses.append(httpx.Response(200, json={"request_id": 555.0, "tail": 100}))
        responses.append(
            httpx.Response(200, json={"id": 30, "logs": "nginx access log", "request_id": 555.0})
        )
        result = client.apps.nginx_logs("acme", 42, "example.com")
        assert result.logs == "nginx access log"

    def test_nginx_logs_polls_until_ready(
        self, mock_client: tuple[Appliku, list[httpx.Response]], monkeypatch: pytest.MonkeyPatch
    ) -> None:
        monkeypatch.setattr("appliku.resources.apps.time.sleep", lambda _: None)
        client, responses = mock_client
        responses.append(httpx.Response(200, json={"request_id": 666.0, "tail": 100}))
        responses.append(httpx.Response(200, json={"id": 31, "logs": None, "request_id": 666.0}))
        responses.append(
            httpx.Response(200, json={"id": 32, "logs": "ready now", "request_id": 666.0})
        )
        result = client.apps.nginx_logs("acme", 42, "example.com")
        assert result.logs == "ready now"
