"""Integration tests for the login gate: /api/auth/* and require_auth."""

import pytest
from agenteval.config.settings import Settings
from agenteval.web.app import app
from agenteval.web.deps import get_db
from fastapi.testclient import TestClient
from sqlmodel import Session, SQLModel, create_engine


@pytest.fixture()
def client_with_db(tmp_path):
    from agenteval.storage.db import (  # noqa: F401
        EvalResultDB,
        EvalRunDB,
        EvalTargetDB,
        ScenarioDB,
        TurnDB,
    )
    engine = create_engine(
        f"sqlite:///{tmp_path / 'auth_api.db'}",
        connect_args={"check_same_thread": False},
    )
    SQLModel.metadata.create_all(engine)
    session = Session(engine)

    def override_get_db():
        try:
            yield session
        finally:
            pass

    app.dependency_overrides[get_db] = override_get_db
    client = TestClient(app)
    yield client
    app.dependency_overrides.clear()
    session.close()


def _patch_settings(monkeypatch, **kwargs):
    settings = Settings(_env_file=None, **kwargs)
    from agenteval.web import deps as deps_module
    from agenteval.web.routers import auth as auth_module

    monkeypatch.setattr(deps_module, "get_settings", lambda: settings)
    monkeypatch.setattr(auth_module, "get_settings", lambda: settings)
    return settings


def test_no_credentials_configured_is_open(client_with_db, monkeypatch):
    _patch_settings(monkeypatch)
    assert client_with_db.get("/api/targets").status_code == 200
    status = client_with_db.get("/api/auth/status").json()
    assert status == {"auth_required": False, "authenticated": True}


def test_login_disabled_returns_400(client_with_db, monkeypatch):
    _patch_settings(monkeypatch)
    resp = client_with_db.post("/api/auth/login", json={"password": "whatever"})
    assert resp.status_code == 400


def test_admin_password_gates_api(client_with_db, monkeypatch):
    _patch_settings(monkeypatch, admin_password="s3cret")

    # No credentials → 401.
    assert client_with_db.get("/api/targets").status_code == 401

    # Wrong password → 401.
    assert client_with_db.post("/api/auth/login", json={"password": "nope"}).status_code == 401

    # Correct password → token that unlocks the API.
    token = client_with_db.post("/api/auth/login", json={"password": "s3cret"}).json()["token"]
    resp = client_with_db.get("/api/targets", headers={"X-Auth-Token": token})
    assert resp.status_code == 200

    status = client_with_db.get("/api/auth/status", headers={"X-Auth-Token": token}).json()
    assert status == {"auth_required": True, "authenticated": True}
    assert client_with_db.get("/api/auth/status").json()["authenticated"] is False


def test_api_key_still_works_alongside_login(client_with_db, monkeypatch):
    _patch_settings(monkeypatch, admin_password="s3cret", api_key="machine-key")

    assert client_with_db.get("/api/targets").status_code == 401
    assert client_with_db.get("/api/targets", headers={"X-API-Key": "machine-key"}).status_code == 200
    assert client_with_db.get("/api/targets", headers={"X-API-Key": "wrong"}).status_code == 401


def test_health_stays_open(client_with_db, monkeypatch):
    _patch_settings(monkeypatch, admin_password="s3cret")
    assert client_with_db.get("/api/health").status_code == 200
