"""Nextcloud initial setup scenario.

Automates the first-time setup wizard for a fresh Nextcloud installation.
This scenario:
1. Navigates to the Nextcloud instance
2. Creates the admin account
3. Optionally skips recommended apps installation
4. Verifies successful login to the dashboard
"""

from typing import Any

from playwright.async_api import Page, expect

from app.playwright_scenarios import register_scenario
from app.playwright_scenarios.base import BaseScenario, ScenarioOptions, ScenarioResult


@register_scenario
class NextcloudInitialSetup(BaseScenario):
    """Automate Nextcloud first-time setup wizard.

    This scenario handles the initial admin account creation when
    Nextcloud is freshly installed. It's idempotent - if setup is
    already complete, it will detect this and succeed.

    Required inputs:
        base_url: The Nextcloud instance URL (e.g., https://cloud.example.com)
        admin_username: Username for the admin account
        admin_password: Password for the admin account

    Optional inputs:
        skip_recommended_apps: Skip the recommended apps step (default: True)

    Result data:
        admin_created: Whether a new admin was created (False if already setup)
        login_successful: Whether login to dashboard succeeded
        setup_skipped: True if Nextcloud was already configured
    """

    @property
    def name(self) -> str:
        return "nextcloud_initial_setup"

    @property
    def required_inputs(self) -> list[str]:
        return ["base_url", "admin_username", "admin_password"]

    @property
    def optional_inputs(self) -> list[str]:
        return ["skip_recommended_apps"]

    @property
    def description(self) -> str:
        return "Automate Nextcloud first-time admin setup wizard"

    async def execute(
        self,
        page: Page,
        inputs: dict[str, Any],
        options: ScenarioOptions,
    ) -> ScenarioResult:
        """Execute the Nextcloud initial setup.

        Args:
            page: Playwright Page object
            inputs: Scenario inputs (base_url, admin_username, admin_password)
            options: Scenario options

        Returns:
            ScenarioResult with setup status
        """
        base_url = inputs["base_url"].rstrip("/")
        admin_username = inputs["admin_username"]
        admin_password = inputs["admin_password"]
        skip_recommended_apps = inputs.get("skip_recommended_apps", True)

        screenshots = []
        result_data = {
            "admin_created": False,
            "login_successful": False,
            "setup_skipped": False,
        }

        try:
            # Navigate to Nextcloud
            await page.goto(base_url, wait_until="networkidle")

            # Check if we're on the setup page or login page
            current_url = page.url

            # Detect if setup is already complete (redirects to login)
            if "/login" in current_url or await page.locator('input[name="user"]').count() > 0:
                # Already configured, try to login
                result_data["setup_skipped"] = True
                login_success = await self._try_login(
                    page, admin_username, admin_password
                )
                result_data["login_successful"] = login_success

                return ScenarioResult(
                    success=login_success,
                    data=result_data,
                    screenshots=screenshots,
                    error=None if login_success else "Login failed - check credentials",
                )

            # We're on the setup page - create admin account
            # Wait for the setup form to be visible
            admin_user_input = page.locator('input[id="adminlogin"], input[name="adminlogin"]')
            await admin_user_input.wait_for(state="visible", timeout=10000)

            # Fill in admin credentials
            await admin_user_input.fill(admin_username)

            admin_pass_input = page.locator('input[id="adminpass"], input[name="adminpass"]')
            await admin_pass_input.fill(admin_password)

            # Check for data directory input (may or may not be present)
            data_dir_input = page.locator('input[id="directory"]')
            if await data_dir_input.count() > 0 and await data_dir_input.is_visible():
                # Keep default data directory
                pass

            # Click install/finish setup button
            # Nextcloud uses various button texts depending on version
            install_button = page.locator(
                'input[type="submit"][value*="Install"], '
                'input[type="submit"][value*="Finish"], '
                'button:has-text("Install"), '
                'button:has-text("Finish setup")'
            )
            await install_button.click()

            # Wait for installation to complete (this can take a while)
            # Look for either dashboard or recommended apps screen
            try:
                await page.wait_for_url(
                    lambda url: "/apps" in url or "/index.php" in url or "dashboard" in url.lower(),
                    timeout=120000,  # 2 minutes for installation
                )
            except Exception:
                # May be on recommended apps screen
                pass

            result_data["admin_created"] = True

            # Handle recommended apps screen if present
            if skip_recommended_apps:
                skip_button = page.locator(
                    'button:has-text("Skip"), '
                    'a:has-text("Skip"), '
                    '.skip-button'
                )
                if await skip_button.count() > 0:
                    await skip_button.first.click()
                    await page.wait_for_load_state("networkidle")

            # Verify we're logged in by checking for user menu or dashboard elements
            dashboard_indicators = page.locator(
                '#user-menu, '
                '.user-menu, '
                '[data-id="dashboard"], '
                '#nextcloud, '
                '.app-dashboard'
            )

            try:
                await dashboard_indicators.first.wait_for(state="visible", timeout=30000)
                result_data["login_successful"] = True
            except Exception:
                # Try one more check - look for any indication we're logged in
                if await page.locator('.header-menu').count() > 0:
                    result_data["login_successful"] = True

            # Take a screenshot of the final state if requested
            if options.screenshot_on_success and options.artifacts_dir:
                screenshot_path = options.artifacts_dir / "setup_complete.png"
                await page.screenshot(path=str(screenshot_path))
                screenshots.append(str(screenshot_path))

            success = result_data["admin_created"] and result_data["login_successful"]
            return ScenarioResult(
                success=success,
                data=result_data,
                screenshots=screenshots,
                error=None if success else "Setup completed but verification failed",
            )

        except Exception as e:
            return ScenarioResult(
                success=False,
                data=result_data,
                screenshots=screenshots,
                error=f"Nextcloud setup failed: {str(e)}",
            )

    async def _try_login(self, page: Page, username: str, password: str) -> bool:
        """Attempt to login to an already-configured Nextcloud.

        Args:
            page: Playwright Page object (should be on login page)
            username: Username to login with
            password: Password to login with

        Returns:
            True if login succeeded, False otherwise
        """
        try:
            # Fill login form
            await page.locator('input[name="user"]').fill(username)
            await page.locator('input[name="password"]').fill(password)

            # Submit login
            await page.locator('input[type="submit"], button[type="submit"]').click()

            # Wait for redirect to dashboard
            await page.wait_for_url(
                lambda url: "/login" not in url,
                timeout=30000,
            )

            # Check for login error message
            error_msg = page.locator('.warning, .error, [class*="error"]')
            if await error_msg.count() > 0 and await error_msg.first.is_visible():
                return False

            return True

        except Exception:
            return False
