"""
Manual test for Nextcloud impersonate API.

This script tests using the Nextcloud impersonate app to allow
admin users to act on behalf of other users.

This is NOT the same as OAuth token exchange, but could serve
as a workaround for background operations.

Usage:
    # Start app container
    docker compose up -d app

    # Run the test
    uv run python tests/manual/test_nextcloud_impersonate.py
"""

import asyncio
import logging
import os
import sys

# Add parent directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../.."))

import httpx

# Setup logging
logging.basicConfig(
    level=logging.INFO, format="%(levelname)-8s | %(name)-30s | %(message)s"
)
logger = logging.getLogger(__name__)


async def main():
    """Test Nextcloud impersonate API"""

    # Configuration
    nextcloud_host = os.getenv("NEXTCLOUD_HOST", "http://localhost:8080")
    admin_user = os.getenv("NEXTCLOUD_USERNAME", "admin")
    admin_password = os.getenv("NEXTCLOUD_PASSWORD", "admin")
    target_user = "testuser"  # We'll create this user

    logger.info("=" * 80)
    logger.info("Nextcloud Impersonate API Test")
    logger.info("=" * 80)
    logger.info(f"Nextcloud: {nextcloud_host}")
    logger.info(f"Admin user: {admin_user}")
    logger.info(f"Target user: {target_user}")
    logger.info("")

    async with httpx.AsyncClient() as client:
        # Step 1: Login as admin and get session
        logger.info("Step 1: Logging in as admin...")
        login_response = await client.post(
            f"{nextcloud_host}/login",
            data={
                "user": admin_user,
                "password": admin_password,
            },
            follow_redirects=True,
        )

        if login_response.status_code != 200:
            logger.error(f"❌ Admin login failed: {login_response.status_code}")
            return 1

        # Get requesttoken from response
        requesttoken = None
        for cookie in client.cookies.jar:
            if cookie.name == "nc_session":
                logger.info(f"✓ Admin logged in, session: {cookie.value[:20]}...")
                break

        logger.info("")

        # Step 2: Create test user if doesn't exist
        logger.info(f"Step 2: Creating test user '{target_user}'...")
        create_user_response = await client.post(
            f"{nextcloud_host}/ocs/v1.php/cloud/users",
            auth=(admin_user, admin_password),
            data={
                "userid": target_user,
                "password": "testpassword123",
            },
            headers={"OCS-APIRequest": "true"},
        )

        if create_user_response.status_code in (200, 400):  # 400 if already exists
            logger.info("✓ Test user ready")
        else:
            logger.warning(
                f"User creation response: {create_user_response.status_code}"
            )

        # Make sure user has logged in at least once (requirement for impersonation)
        logger.info(f"  Performing initial login for {target_user}...")
        await client.post(
            f"{nextcloud_host}/login",
            data={
                "user": target_user,
                "password": "testpassword123",
            },
            follow_redirects=True,
        )
        logger.info("✓ Test user has logged in")

        # Re-login as admin
        await client.post(
            f"{nextcloud_host}/login",
            data={
                "user": admin_user,
                "password": admin_password,
            },
            follow_redirects=True,
        )

        logger.info("")

        # Step 3: Get CSRF token for impersonate request
        logger.info("Step 3: Getting CSRF token...")

        # Try to get token from settings page
        settings_response = await client.get(
            f"{nextcloud_host}/settings/users",
            follow_redirects=True,
        )

        # Extract requesttoken from HTML
        import re

        token_match = re.search(r'data-requesttoken="([^"]+)"', settings_response.text)
        if token_match:
            requesttoken = token_match.group(1)
            logger.info(f"✓ CSRF token acquired: {requesttoken[:20]}...")
        else:
            logger.error("❌ Could not extract CSRF token from page")
            return 1

        logger.info("")

        # Step 4: Call impersonate API
        logger.info(f"Step 4: Impersonating user '{target_user}'...")
        impersonate_response = await client.post(
            f"{nextcloud_host}/apps/impersonate/user",
            data={
                "userId": target_user,
            },
            headers={
                "requesttoken": requesttoken,
                "Content-Type": "application/x-www-form-urlencoded",
            },
        )

        if impersonate_response.status_code != 200:
            logger.error(f"❌ Impersonate failed: {impersonate_response.status_code}")
            logger.error(f"Response: {impersonate_response.text}")
            return 1

        logger.info("✓ Impersonation successful")
        logger.info("")

        # Step 5: Test API call as impersonated user
        logger.info("Step 5: Testing API call as impersonated user...")
        capabilities_response = await client.get(
            f"{nextcloud_host}/ocs/v2.php/cloud/capabilities",
            headers={"OCS-APIRequest": "true"},
        )

        if capabilities_response.status_code == 200:
            caps = capabilities_response.json()
            logger.info(f"✓ API call successful as {target_user}")
            logger.info(
                f"  Version: {caps.get('ocs', {}).get('data', {}).get('version', {}).get('string')}"
            )
        else:
            logger.error(f"❌ API call failed: {capabilities_response.status_code}")
            return 1

        logger.info("")

        # Step 6: Get current user to verify impersonation
        logger.info("Step 6: Verifying current user...")
        user_response = await client.get(
            f"{nextcloud_host}/ocs/v2.php/cloud/user",
            headers={"OCS-APIRequest": "true"},
        )

        if user_response.status_code == 200:
            user_data = user_response.json()
            current_user = user_data.get("ocs", {}).get("data", {}).get("id")
            logger.info(f"✓ Current user: {current_user}")

            if current_user == target_user:
                logger.info("  ✓ Successfully impersonating target user!")
            else:
                logger.warning(f"  ⚠ Expected {target_user}, got {current_user}")
        else:
            logger.error(f"❌ User check failed: {user_response.status_code}")

    logger.info("")
    logger.info("=" * 80)
    logger.info("✅ Impersonate API Test PASSED")
    logger.info("=" * 80)
    logger.info("")
    logger.info("Summary:")
    logger.info("  1. Admin can impersonate other users via session-based API")
    logger.info("  2. Impersonated session can access APIs as that user")
    logger.info("  3. Requires admin credentials and CSRF token")
    logger.info("")
    logger.info("Limitations:")
    logger.info("  - Session-based (not stateless like OAuth)")
    logger.info("  - Requires admin credentials")
    logger.info("  - Target user must have logged in at least once")
    logger.info("  - Not suitable for distributed/background workers")
    logger.info("")
    logger.info("For background operations, consider:")
    logger.info("  - Use service account with appropriate permissions")
    logger.info("  - Or implement proper OAuth delegation (RFC 8693)")
    logger.info("")

    return 0


if __name__ == "__main__":
    exit_code = asyncio.run(main())
    sys.exit(exit_code)
