"""
Tests for the /api/v1/setup endpoints.

Covers initial setup status, admin user setup, and system configuration.
"""

import pytest
from fastapi.testclient import TestClient

from app.api.api_v1.endpoints.setup import setup_status
from app.core.security import _api_keys, add_api_key
from app.models.setting import Setting


@pytest.fixture(autouse=True)
def reset_setup_status():
    """Reset in-memory setup_status before each test to avoid state leakage."""
    original = dict(setup_status)
    setup_status["is_setup_complete"] = False
    setup_status["admin_email"] = None
    setup_status["app_name"] = "DMARQ"
    yield
    setup_status.update(original)


class TestSetupStatus:
    """Tests for GET /api/v1/setup/status"""

    def test_initial_status_not_complete(self, client: TestClient):
        response = client.get("/api/v1/setup/status")
        assert response.status_code == 200
        data = response.json()
        assert data["is_setup_complete"] is False
        assert data["app_name"] == "DMARQ"

    def test_status_after_system_setup(self, client: TestClient):
        client.post(
            "/api/v1/setup/system",
            json={"app_name": "MyApp", "base_url": "https://example.com"},
        )
        response = client.get("/api/v1/setup/status")
        data = response.json()
        assert data["is_setup_complete"] is True
        assert data["app_name"] == "MyApp"

    def test_status_reads_persisted_setup_state_after_memory_reset(
        self, client: TestClient, db_session
    ):
        db_session.add(
            Setting(
                key="setup.is_complete",
                value="true",
                description="Whether initial setup has been completed",
                value_type="boolean",
                category="setup",
            )
        )
        db_session.add(
            Setting(
                key="general.app_name",
                value="Persisted DMARQ",
                description="Application display name shown in the UI",
                value_type="string",
                category="general",
            )
        )
        db_session.commit()
        setup_status["is_setup_complete"] = False
        setup_status["app_name"] = "DMARQ"

        response = client.get("/api/v1/setup/status")

        assert response.status_code == 200
        data = response.json()
        assert data["is_setup_complete"] is True
        assert data["app_name"] == "Persisted DMARQ"


class TestSetupAdmin:
    """Tests for POST /api/v1/setup/admin"""

    def test_admin_setup_succeeds_on_first_call(self, client: TestClient):
        response = client.post(
            "/api/v1/setup/admin",
            json={
                "email": "admin@example.com",
                "username": "admin",
                "password": "test-placeholder-password",
            },
        )
        assert response.status_code == 201
        assert "message" in response.json()

    def test_admin_setup_requires_auth_if_already_complete(self, client: TestClient):
        setup_status["is_setup_complete"] = True

        response = client.post(
            "/api/v1/setup/admin",
            json={
                "email": "admin2@example.com",
                "username": "admin2",
                "password": "pass",
            },
        )

        assert response.status_code == 401

    def test_admin_setup_fails_if_already_complete(self, client: TestClient):
        # Mark setup as complete
        setup_status["is_setup_complete"] = True
        api_key = "a" * 64
        add_api_key(api_key)

        try:
            response = client.post(
                "/api/v1/setup/admin",
                json={
                    "email": "admin2@example.com",
                    "username": "admin2",
                    "password": "pass",
                },
                headers={"X-API-Key": api_key},
            )
        finally:
            _api_keys.discard(api_key)

        assert response.status_code == 400
        assert "already completed" in response.json()["detail"]

    def test_admin_setup_rejects_invalid_email(self, client: TestClient):
        response = client.post(
            "/api/v1/setup/admin",
            json={
                "email": "not-an-email",
                "username": "admin",
                "password": "pass",
            },
        )
        assert response.status_code == 422


class TestSetupSystem:
    """Tests for POST /api/v1/setup/system"""

    def test_system_setup_saves_app_name(self, client: TestClient):
        response = client.post(
            "/api/v1/setup/system",
            json={"app_name": "DMARQ Custom", "base_url": "https://dmarq.example.com"},
        )
        assert response.status_code == 200
        assert "message" in response.json()
        assert setup_status["app_name"] == "DMARQ Custom"
        assert setup_status["is_setup_complete"] is True

    def test_system_setup_marks_complete(self, client: TestClient):
        assert setup_status["is_setup_complete"] is False
        client.post(
            "/api/v1/setup/system",
            json={"app_name": "Test", "base_url": "https://test.example.com"},
        )
        assert setup_status["is_setup_complete"] is True

    def test_system_setup_requires_auth_if_already_complete(self, client: TestClient):
        setup_status["is_setup_complete"] = True

        response = client.post(
            "/api/v1/setup/system",
            json={"app_name": "Changed", "base_url": "https://changed.example.com"},
        )

        assert response.status_code == 401

    def test_system_setup_requires_auth_if_persisted_complete_after_restart(
        self, client: TestClient
    ):
        first_response = client.post(
            "/api/v1/setup/system",
            json={"app_name": "DMARQ", "base_url": "https://example.com"},
        )
        assert first_response.status_code == 200
        setup_status["is_setup_complete"] = False

        response = client.post(
            "/api/v1/setup/system",
            json={"app_name": "Changed", "base_url": "https://changed.example.com"},
        )

        assert response.status_code == 401

    def test_system_setup_allows_authenticated_updates_after_complete(self, client: TestClient):
        setup_status["is_setup_complete"] = True
        api_key = "b" * 64
        add_api_key(api_key)

        try:
            response = client.post(
                "/api/v1/setup/system",
                json={"app_name": "Changed", "base_url": "https://changed.example.com"},
                headers={"X-API-Key": api_key},
            )
        finally:
            _api_keys.discard(api_key)

        assert response.status_code == 200
        assert setup_status["app_name"] == "Changed"
