# -*- coding: utf-8 -*-
"""CRUD tests for Users entity in ContextForge Admin UI.

Location: ./tests/playwright/entities/test_users.py
Copyright 2026
SPDX-License-Identifier: Apache-2.0
Authors: Marek Dano
"""

# Third-Party
import pytest

# Local
from ..pages.admin_utils import cleanup_user
from ..pages.users_page import UsersPage


def _create_user_and_navigate(users_page: UsersPage, test_user_data: dict) -> None:
    """Helper: create a user via the UI form and reload to see the change.

    The HTMX in-place refresh does not update the user list reliably,
    so we wait for any pending JS activity, then do a full page reload
    and re-navigate to the users tab.
    """
    users_page.navigate_to_users_tab()
    users_page.wait_for_visible(users_page.create_user_form, timeout=15000)

    with users_page.page.expect_response(lambda response: "/admin/users" in response.url and response.request.method == "POST" and "/partial" not in response.url) as response_info:
        users_page.create_user(
            email=test_user_data["email"],
            full_name=test_user_data["full_name"],
            password=test_user_data["password"],
        )
    response = response_info.value
    assert response.status < 400, f"User creation failed with status {response.status}"

    # Reload the page to pick up the newly created user
    users_page.reload_and_navigate_to_users()

    # Verify user now appears in the list
    users_page.wait_for_user_visible(test_user_data["email"])


@pytest.mark.ui
@pytest.mark.crud
class TestUsersCRUD:
    """CRUD tests for Users entity via the admin UI."""

    def test_create_user(self, users_page: UsersPage, test_user_data):
        """Test creating a new user via the admin UI form."""
        _create_user_and_navigate(users_page, test_user_data)
        assert users_page.user_exists_in_list(test_user_data["email"])

        # Cleanup
        cleanup_user(users_page.page, test_user_data["email"])

    def test_edit_user(self, users_page: UsersPage, test_user_data):
        """Test editing a user's full name via the edit modal."""
        _create_user_and_navigate(users_page, test_user_data)

        # Edit user
        updated_name = f"Updated {test_user_data['full_name']}"
        users_page.click_edit_button(test_user_data["email"])

        with users_page.page.expect_response(lambda response: "/update" in response.url and response.request.method == "POST") as response_info:
            users_page.submit_edit_form(full_name=updated_name)
        response = response_info.value
        assert response.status < 400, f"User edit failed with status {response.status}"

        # Reload the page to pick up the edit
        users_page.reload_and_navigate_to_users()

        # Verify the updated name appears in the user card
        card = users_page.find_user_card(test_user_data["email"])
        card_text = card.text_content() or ""
        assert updated_name in card_text

        # Cleanup
        cleanup_user(users_page.page, test_user_data["email"])

    def test_delete_user(self, users_page: UsersPage, test_user_data):
        """Test deleting a user via the Delete button (with confirm dialog)."""
        _create_user_and_navigate(users_page, test_user_data)

        # Delete user (accepts hx-confirm dialog)
        with users_page.page.expect_response(lambda response: "/admin/users" in response.url and response.request.method == "DELETE") as response_info:
            users_page.click_delete(test_user_data["email"])
        response = response_info.value
        assert response.status < 400, f"User deletion failed with status {response.status}"

        # The delete uses hx-swap="outerHTML" on closest .user-card,
        # so the card is replaced in-place.
        users_page.page.wait_for_timeout(1000)
        assert not users_page.user_exists_in_list(test_user_data["email"])

    def test_deactivate_user(self, users_page: UsersPage, test_user_data):
        """Test deactivating a user via the Deactivate button."""
        _create_user_and_navigate(users_page, test_user_data)

        # Deactivate user (in-place HTMX outerHTML swap on .user-card)
        with users_page.page.expect_response(lambda response: "/deactivate" in response.url and response.request.method == "POST") as response_info:
            users_page.click_deactivate(test_user_data["email"])
        response = response_info.value
        assert response.status < 400, f"User deactivation failed with status {response.status}"

        # Wait for card to update via HTMX outerHTML swap
        users_page.page.wait_for_timeout(1000)
        assert users_page.user_has_badge(test_user_data["email"], "Inactive")

        # Cleanup
        cleanup_user(users_page.page, test_user_data["email"])

    def test_activate_user(self, users_page: UsersPage, test_user_data):
        """Test activating a previously deactivated user."""
        _create_user_and_navigate(users_page, test_user_data)

        # Deactivate user first (in-place swap)
        with users_page.page.expect_response(lambda response: "/deactivate" in response.url and response.request.method == "POST") as deactivate_info:
            users_page.click_deactivate(test_user_data["email"])
        assert deactivate_info.value.status < 400, f"User deactivation (setup) failed with status {deactivate_info.value.status}"  # nosec B101
        users_page.page.wait_for_timeout(1000)

        # Now activate user (in-place swap)
        with users_page.page.expect_response(lambda response: "/activate" in response.url and response.request.method == "POST") as response_info:
            users_page.click_activate(test_user_data["email"])
        response = response_info.value
        assert response.status < 400, f"User activation failed with status {response.status}"

        # Wait for card to update via HTMX outerHTML swap
        users_page.page.wait_for_timeout(1000)
        assert users_page.user_has_badge(test_user_data["email"], "Active")

        # Cleanup
        cleanup_user(users_page.page, test_user_data["email"])

    def test_force_password_change(self, users_page: UsersPage, test_user_data):
        """Test forcing a password change on a user."""
        _create_user_and_navigate(users_page, test_user_data)

        # Force password change (in-place swap)
        with users_page.page.expect_response(lambda response: "/force-password-change" in response.url and response.request.method == "POST") as response_info:
            users_page.click_force_password_change(test_user_data["email"])
        response = response_info.value
        assert response.status < 400, f"Force password change failed with status {response.status}"

        # Wait for card to update via HTMX outerHTML swap
        users_page.page.wait_for_timeout(1000)
        assert users_page.user_has_badge(test_user_data["email"], "Password Change Required")

        # Cleanup
        cleanup_user(users_page.page, test_user_data["email"])
