"""High priority user API tests."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest
from fastapi.testclient import TestClient

if TYPE_CHECKING:
    from sqlalchemy.orm import Session
    from backend.db.models import User


class TestUserListing:
    """Test user listing endpoints."""

    def test_list_users_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        admin_user: "User",
    ):
        """Verify users list (admin only)."""
        response = test_client.get(
            "/api/v1/users",
            headers=auth_headers,
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "items" in data
        assert "total" in data

    def test_list_users_non_admin(
        self,
        test_client: TestClient,
        regular_auth_headers: dict,
        admin_user,  # Ensure an admin exists to prevent bootstrap
    ):
        """Verify 403 for non-admin users."""
        response = test_client.get(
            "/api/v1/users",
            headers=regular_auth_headers,
        )
        
        assert response.status_code in [403, 401]

    def test_list_users_with_pagination(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify pagination."""
        response = test_client.get(
            "/api/v1/users",
            headers=auth_headers,
            params={"page": 1, "page_size": 10},
        )
        
        assert response.status_code == 200
        data = response.json()
        assert "items" in data


class TestUserCRUD:
    """Test user CRUD endpoints."""

    def test_create_user_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify user creation (admin only)."""
        response = test_client.post(
            "/api/v1/users",
            headers=auth_headers,
            json={
                "username": "newuser",
                "email": "newuser@example.com",
                "full_name": "New User",
                "password": "password123",
            },
        )
        
        assert response.status_code == 201
        data = response.json()
        assert data["username"] == "newuser"
        assert data["email"] == "newuser@example.com"

    def test_create_user_duplicate_email(
        self,
        test_client: TestClient,
        auth_headers: dict,
        admin_user: "User",
    ):
        """Verify 400 with duplicate email."""
        response = test_client.post(
            "/api/v1/users",
            headers=auth_headers,
            json={
                "username": "differentuser",
                "email": admin_user.email,  # Duplicate email
                "full_name": "Different User",
                "password": "password123",
            },
        )
        
        assert response.status_code == 400

    def test_create_user_duplicate_username(
        self,
        test_client: TestClient,
        auth_headers: dict,
        admin_user: "User",
    ):
        """Verify 400 with duplicate username."""
        response = test_client.post(
            "/api/v1/users",
            headers=auth_headers,
            json={
                "username": admin_user.username,  # Duplicate username
                "email": "different@example.com",
                "full_name": "Different User",
                "password": "password123",
            },
        )
        
        assert response.status_code == 400

    def test_get_user_by_id_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        admin_user: "User",
    ):
        """Verify user retrieval."""
        response = test_client.get(
            f"/api/v1/users/{admin_user.id}",
            headers=auth_headers,
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["id"] == admin_user.id
        assert data["username"] == admin_user.username

    def test_get_user_by_id_not_found(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 404 for non-existent user."""
        response = test_client.get(
            "/api/v1/users/99999",
            headers=auth_headers,
        )
        
        assert response.status_code == 404

    def test_update_user_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        admin_user: "User",
    ):
        """Verify user update."""
        response = test_client.put(
            f"/api/v1/users/{admin_user.id}",
            headers=auth_headers,
            json={
                "email": admin_user.email,
                "full_name": "Updated Name",
            },
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["full_name"] == "Updated Name"

    def test_delete_user_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        test_db_session: "Session",
    ):
        """Verify user deletion."""
        from backend.db.models import User
        from backend.utils.password import hash_password
        from backend.constants.roles import DEFAULT_USER_ROLE
        
        # Create a user to delete
        user = User(
            username="deleteuser",
            email="delete@example.com",
            password_hash=hash_password("password"),
            full_name="Delete User",
            is_admin=False,
            is_active=True,
            role=DEFAULT_USER_ROLE,
        )
        test_db_session.add(user)
        test_db_session.commit()
        test_db_session.refresh(user)
        
        response = test_client.delete(
            f"/api/v1/users/{user.id}",
            headers=auth_headers,
        )
        
        # Returns 204 when deleted, 200 when set to inactive (has linked data)
        assert response.status_code in [200, 204]

    def test_delete_user_non_admin(
        self,
        test_client: TestClient,
        regular_auth_headers: dict,
        admin_user: "User",
    ):
        """Verify 403 for non-admin."""
        response = test_client.delete(
            f"/api/v1/users/{admin_user.id}",
            headers=regular_auth_headers,
        )
        
        assert response.status_code in [403, 401]


class TestUserActivation:
    """Test user activation endpoints."""

    def test_activate_user_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        inactive_user: "User",
    ):
        """Verify user activation."""
        response = test_client.put(
            f"/api/v1/users/{inactive_user.id}",
            headers=auth_headers,
            json={
                "email": inactive_user.email,
                "full_name": inactive_user.full_name or inactive_user.username,
                "is_active": True,
            },
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["is_active"] is True

    def test_deactivate_user_success(
        self,
        test_client: TestClient,
        auth_headers: dict,
        regular_user: "User",
    ):
        """Verify user deactivation."""
        response = test_client.put(
            f"/api/v1/users/{regular_user.id}",
            headers=auth_headers,
            json={
                "email": regular_user.email,
                "full_name": regular_user.full_name or regular_user.username,
                "is_active": False,
            },
        )
        
        assert response.status_code == 200
        data = response.json()
        assert data["is_active"] is False

    def test_activate_user_not_found(
        self,
        test_client: TestClient,
        auth_headers: dict,
    ):
        """Verify 404 handling."""
        response = test_client.put(
            "/api/v1/users/99999",
            headers=auth_headers,
            json={
                "email": "nonexistent@example.com",
                "full_name": "Nonexistent User",
                "is_active": True,
            },
        )
        
        assert response.status_code == 404

