from __future__ import annotations

from pathlib import Path
from typing import Any, Dict

from flask import Flask, jsonify

from lawrisk.api import auth as auth_module
from lawrisk.api.auth import auth_bp


def build_test_app() -> Flask:
    base_path = Path(__file__).resolve().parents[1]
    app = Flask(
        __name__,
        template_folder=str(base_path / "templates"),
        static_folder=str(base_path / "static"),
    )
    app.secret_key = "test-secret"
    app.register_blueprint(auth_bp)
    app.config.update(TESTING=True)

    @app.route("/protected-json")
    @auth_module.login_required
    def protected_json() -> Any:
        return jsonify({"ok": True})

    @app.route("/protected-page")
    @auth_module.login_required
    def protected_page() -> Any:
        return "secret"

    return app


def test_login_success(monkeypatch) -> None:
    app = build_test_app()
    client = app.test_client()

    fake_user: Dict[str, Any] = {
        "id": "user-1",
        "username": "admin",
        "display_name": "Admin",
        "role": "admin",
        "grade": 100,
        "is_active": True,
        "password_hash": "hash",
    }

    monkeypatch.setattr(auth_module, "get_user_by_username", lambda _: fake_user)
    monkeypatch.setattr(auth_module, "verify_password", lambda *_: True)

    resp = client.post("/auth/login", json={"username": "admin", "password": "secret"})
    assert resp.status_code == 200
    data = resp.get_json()
    assert data["user"]["role"] == "admin"
    assert data["redirect"] == "/"
    with client.session_transaction() as sess:
        assert sess[auth_module.SESSION_USER_KEY]["username"] == "admin"


def test_login_invalid_credentials(monkeypatch) -> None:
    app = build_test_app()
    client = app.test_client()

    monkeypatch.setattr(auth_module, "get_user_by_username", lambda *_: None)

    resp = client.post("/auth/login", json={"username": "ghost", "password": "bad"})
    assert resp.status_code == 401
    assert resp.get_json()["error"] == "invalid credentials"


def test_login_success_honors_next(monkeypatch) -> None:
    app = build_test_app()
    client = app.test_client()

    fake_user: Dict[str, Any] = {
        "id": "user-1",
        "username": "admin",
        "display_name": "Admin",
        "role": "admin",
        "grade": 100,
        "is_active": True,
        "password_hash": "hash",
    }

    monkeypatch.setattr(auth_module, "get_user_by_username", lambda _: fake_user)
    monkeypatch.setattr(auth_module, "verify_password", lambda *_: True)

    resp = client.post(
        "/auth/login?next=/fs-ai-asistant/api/workflow/lawrisk/db_admin",
        json={"username": "admin", "password": "secret"},
    )
    assert resp.status_code == 200
    assert (
        resp.get_json()["redirect"] == "/fs-ai-asistant/api/workflow/lawrisk/db_admin"
    )


def test_me_endpoint_requires_session() -> None:
    app = build_test_app()
    client = app.test_client()

    resp = client.get("/auth/me")
    assert resp.status_code == 401

    with client.session_transaction() as sess:
        sess[auth_module.SESSION_USER_KEY] = {
            "id": "user-2",
            "username": "analyst",
            "display_name": "Data Analyst",
            "role": "reviewer",
            "grade": 20,
        }

    resp2 = client.get("/auth/me")
    assert resp2.status_code == 200
    assert resp2.get_json()["user"]["role"] == "reviewer"


def test_login_required_returns_json_error_for_api() -> None:
    app = build_test_app()
    client = app.test_client()

    resp = client.get("/protected-json", headers={"Accept": "application/json"})
    assert resp.status_code == 401
    assert resp.get_json()["error"] == "authentication required"


def test_login_required_redirects_for_html() -> None:
    app = build_test_app()
    client = app.test_client()

    resp = client.get("/protected-page", headers={"Accept": "text/html"})
    assert resp.status_code == 302
    assert "/fs-ai-asistant/api/workflow/lawrisk/login" in resp.headers["Location"]
