"""Tests for authentication endpoints."""
import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.security import hash_password
from app.models.utilisateur import Utilisateur


SIGNUP_PAYLOAD = {
    "email": "test@inphb.ci",
    "motDePasse": "TestPass123!",
    "nom": "Konan",
    "prenom": "Ama",
}


@pytest.mark.asyncio
async def test_signup_success(client: AsyncClient):
    response = await client.post("/api/v1/auth/signup", json=SIGNUP_PAYLOAD)
    assert response.status_code == 201
    body = response.json()
    assert body["statusCode"] == 201
    assert body["data"]["email"] == SIGNUP_PAYLOAD["email"]


@pytest.mark.asyncio
async def test_signup_duplicate_email(client: AsyncClient):
    await client.post("/api/v1/auth/signup", json=SIGNUP_PAYLOAD)
    response = await client.post("/api/v1/auth/signup", json=SIGNUP_PAYLOAD)
    assert response.status_code == 409


@pytest.mark.asyncio
async def test_login_success(client: AsyncClient):
    await client.post("/api/v1/auth/signup", json=SIGNUP_PAYLOAD)
    response = await client.post(
        "/api/v1/auth/login",
        json={"email": SIGNUP_PAYLOAD["email"], "motDePasse": SIGNUP_PAYLOAD["motDePasse"]},
    )
    assert response.status_code == 200
    body = response.json()
    assert "token" in body["data"]
    assert "refreshToken" in body["data"]


@pytest.mark.asyncio
async def test_login_wrong_password(client: AsyncClient):
    await client.post("/api/v1/auth/signup", json=SIGNUP_PAYLOAD)
    response = await client.post(
        "/api/v1/auth/login",
        json={"email": SIGNUP_PAYLOAD["email"], "motDePasse": "wrongpassword"},
    )
    assert response.status_code == 401


@pytest.mark.asyncio
async def test_validate_token(client: AsyncClient):
    await client.post("/api/v1/auth/signup", json=SIGNUP_PAYLOAD)
    login = await client.post(
        "/api/v1/auth/login",
        json={"email": SIGNUP_PAYLOAD["email"], "motDePasse": SIGNUP_PAYLOAD["motDePasse"]},
    )
    token = login.json()["data"]["token"]

    response = await client.get(
        "/api/v1/auth/validate",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 200
    assert response.json()["data"]["valid"] is True


@pytest.mark.asyncio
async def test_logout(client: AsyncClient):
    await client.post("/api/v1/auth/signup", json=SIGNUP_PAYLOAD)
    login = await client.post(
        "/api/v1/auth/login",
        json={"email": SIGNUP_PAYLOAD["email"], "motDePasse": SIGNUP_PAYLOAD["motDePasse"]},
    )
    token = login.json()["data"]["token"]

    logout = await client.post(
        "/api/v1/auth/logout",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert logout.status_code == 204

    # Token should now be invalid
    validate = await client.get(
        "/api/v1/auth/validate",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert validate.status_code == 401


@pytest.mark.asyncio
async def test_admin_created_user_must_change_password_on_first_login(client: AsyncClient, db: AsyncSession):
    admin = Utilisateur(
        email="admin.stats@inphb.ci",
        mot_de_passe_hash=hash_password("AdminPass123!"),
        nom="Admin",
        prenom="Test",
        type_utilisateur="ADMIN_SYSTEME",
        est_actif=True,
    )
    db.add(admin)
    await db.commit()

    admin_login = await client.post(
        "/api/v1/auth/login",
        json={"email": "admin.stats@inphb.ci", "motDePasse": "AdminPass123!"},
    )
    admin_token = admin_login.json()["data"]["token"]

    create_response = await client.post(
        "/api/v1/comptes/",
        headers={"Authorization": f"Bearer {admin_token}"},
        json={
            "email": "new.user@inphb.ci",
            "motDePasse": "TempPass123!",
            "nom": "User",
            "prenom": "New",
            "typeUtilisateur": "UTILISATEUR",
        },
    )
    assert create_response.status_code == 201

    user_login = await client.post(
        "/api/v1/auth/login",
        json={"email": "new.user@inphb.ci", "motDePasse": "TempPass123!"},
    )
    assert user_login.status_code == 200
    assert user_login.json()["data"]["doitChangerMotDePasse"] is True


@pytest.mark.asyncio
async def test_first_login_flag_cleared_after_password_change(client: AsyncClient, db: AsyncSession):
    admin = Utilisateur(
        email="admin.reset@inphb.ci",
        mot_de_passe_hash=hash_password("AdminPass123!"),
        nom="Admin",
        prenom="Reset",
        type_utilisateur="ADMIN_SYSTEME",
        est_actif=True,
    )
    db.add(admin)
    await db.commit()

    admin_login = await client.post(
        "/api/v1/auth/login",
        json={"email": "admin.reset@inphb.ci", "motDePasse": "AdminPass123!"},
    )
    admin_token = admin_login.json()["data"]["token"]

    create_response = await client.post(
        "/api/v1/comptes/",
        headers={"Authorization": f"Bearer {admin_token}"},
        json={
            "email": "change.password@inphb.ci",
            "motDePasse": "TempPass123!",
            "nom": "Change",
            "prenom": "Password",
            "typeUtilisateur": "UTILISATEUR",
        },
    )
    assert create_response.status_code == 201

    first_login = await client.post(
        "/api/v1/auth/login",
        json={"email": "change.password@inphb.ci", "motDePasse": "TempPass123!"},
    )
    user_token = first_login.json()["data"]["token"]
    assert first_login.json()["data"]["doitChangerMotDePasse"] is True

    change_password = await client.put(
        "/api/v1/comptes/me/password",
        headers={"Authorization": f"Bearer {user_token}"},
        json={"ancienMotDePasse": "TempPass123!", "nouveauMotDePasse": "NewPass123!"},
    )
    assert change_password.status_code == 200

    second_login = await client.post(
        "/api/v1/auth/login",
        json={"email": "change.password@inphb.ci", "motDePasse": "NewPass123!"},
    )
    assert second_login.status_code == 200
    assert second_login.json()["data"]["doitChangerMotDePasse"] is False
