"""Umami initial setup scenario.

Automates the first-time setup for a fresh Umami installation.
This scenario:
1. Navigates to the Umami login page
2. Logs in with default credentials (admin / umami)
3. Changes the admin password
4. Optionally adds the first website to track
"""

import secrets
import string
from typing import Any

from playwright.async_api import Page

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


def generate_secure_password(length: int = 24) -> str:
    """Generate a cryptographically secure password.

    Args:
        length: Password length (default: 24)

    Returns:
        A secure random password with mixed characters
    """
    alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
    password = [
        secrets.choice(string.ascii_lowercase),
        secrets.choice(string.ascii_uppercase),
        secrets.choice(string.digits),
        secrets.choice("!@#$%^&*"),
    ]
    password.extend(secrets.choice(alphabet) for _ in range(length - 4))
    password_list = list(password)
    secrets.SystemRandom().shuffle(password_list)
    return "".join(password_list)


@register_scenario
class UmamiInitialSetup(BaseScenario):
    """Automate Umami first-time setup.

    This scenario handles the initial configuration after Umami is deployed.
    Umami ships with default credentials (admin / umami). This scenario
    logs in with those defaults, changes the password, and optionally
    adds the first website to track.

    Required inputs:
        base_url: The Umami instance URL (e.g., https://analytics.example.com)

    Optional inputs:
        admin_password: New password for admin (auto-generated if not provided)
        website_name: Name of the first website to add
        website_url: URL of the first website to track

    Result data:
        setup_completed: Whether initial setup was completed
        admin_password: The new admin password - STORE SECURELY
        password_changed: Whether the default password was changed
        website_added: Whether a website was added
        already_configured: True if default password no longer works
    """

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

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

    @property
    def optional_inputs(self) -> list[str]:
        return ["admin_password", "website_name", "website_url"]

    @property
    def description(self) -> str:
        return "Automate Umami first-time password change and website setup"

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

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

        Returns:
            ScenarioResult with setup status and credentials
        """
        base_url = inputs["base_url"].rstrip("/")
        new_password = inputs.get("admin_password") or generate_secure_password()
        website_name = inputs.get("website_name")
        website_url = inputs.get("website_url")

        screenshots = []
        result_data = {
            "setup_completed": False,
            "admin_password": new_password,
            "password_changed": False,
            "website_added": False,
            "already_configured": False,
        }

        try:
            # Navigate to Umami login page
            login_url = f"{base_url}/login"
            await page.goto(login_url, wait_until="networkidle")

            # Look for login form
            username_input = page.locator(
                'input[name="username"], '
                'input[id="username"], '
                'input[placeholder*="username" i]'
            )
            await username_input.wait_for(state="visible", timeout=10000)

            # Try default credentials: admin / umami
            await username_input.fill("admin")

            password_input = page.locator(
                'input[name="password"], '
                'input[type="password"]'
            ).first
            await password_input.fill("umami")

            # Click login
            login_button = page.locator(
                'button:has-text("Login"), '
                'button:has-text("Sign in"), '
                'button[type="submit"]'
            ).first
            await login_button.click()

            # Wait for navigation
            await page.wait_for_timeout(3000)

            # Check if login succeeded
            current_url = page.url
            if "/login" in current_url:
                # Default password may have already been changed
                error_el = page.locator(
                    '.error, [class*="error"], [class*="alert"]'
                )
                if await error_el.count() > 0:
                    result_data["already_configured"] = True
                    result_data["setup_completed"] = True
                    return ScenarioResult(
                        success=True,
                        data=result_data,
                        screenshots=screenshots,
                        error=None,
                    )

            # Logged in successfully with default password - change it
            # Navigate to profile/settings to change password
            settings_url = f"{base_url}/settings/profile"
            await page.goto(settings_url, wait_until="networkidle")

            # Look for password change form
            current_password_input = page.locator(
                'input[name="currentPassword"], '
                'input[name="current_password"], '
                'input[placeholder*="current" i]'
            ).first

            if await current_password_input.count() > 0:
                await current_password_input.wait_for(state="visible", timeout=10000)
                await current_password_input.fill("umami")

                new_password_input = page.locator(
                    'input[name="newPassword"], '
                    'input[name="new_password"], '
                    'input[placeholder*="new" i]'
                ).first
                await new_password_input.fill(new_password)

                confirm_password_input = page.locator(
                    'input[name="confirmPassword"], '
                    'input[name="confirm_password"], '
                    'input[placeholder*="confirm" i]'
                ).first
                if await confirm_password_input.count() > 0:
                    await confirm_password_input.fill(new_password)

                # Save password
                save_button = page.locator(
                    'button:has-text("Save"), '
                    'button:has-text("Change"), '
                    'button:has-text("Update"), '
                    'button[type="submit"]'
                ).first
                await save_button.click()

                await page.wait_for_timeout(2000)

                # Check for success
                success_el = page.locator(
                    '[class*="success"], '
                    ':has-text("saved"), '
                    ':has-text("updated")'
                )
                if await success_el.count() > 0:
                    result_data["password_changed"] = True
                else:
                    # Assume success if no error visible
                    error_el = page.locator('[class*="error"]')
                    if await error_el.count() == 0:
                        result_data["password_changed"] = True

            # Optionally add first website
            if website_name and website_url:
                websites_url = f"{base_url}/settings/websites"
                await page.goto(websites_url, wait_until="networkidle")

                # Click Add Website button
                add_button = page.locator(
                    'button:has-text("Add website"), '
                    'button:has-text("Add"), '
                    'a:has-text("Add website")'
                ).first

                if await add_button.count() > 0:
                    await add_button.click()
                    await page.wait_for_timeout(1000)

                    # Fill website name
                    name_input = page.locator(
                        'input[name="name"], '
                        'input[placeholder*="name" i]'
                    ).first
                    if await name_input.count() > 0:
                        await name_input.fill(website_name)

                    # Fill website URL/domain
                    url_input = page.locator(
                        'input[name="domain"], '
                        'input[name="url"], '
                        'input[placeholder*="domain" i], '
                        'input[placeholder*="url" i]'
                    ).first
                    if await url_input.count() > 0:
                        await url_input.fill(website_url)

                    # Save
                    save_button = page.locator(
                        'button:has-text("Save"), '
                        'button:has-text("Create"), '
                        'button[type="submit"]'
                    ).first
                    await save_button.click()
                    await page.wait_for_timeout(2000)

                    result_data["website_added"] = True

            result_data["setup_completed"] = True

            # Take final screenshot
            if options.screenshot_on_success and options.artifacts_dir:
                final_path = options.artifacts_dir / "umami_setup_complete.png"
                await page.screenshot(path=str(final_path))
                screenshots.append(str(final_path))

            return ScenarioResult(
                success=True,
                data=result_data,
                screenshots=screenshots,
                error=None,
            )

        except Exception as e:
            if options.screenshot_on_failure and options.artifacts_dir:
                error_path = options.artifacts_dir / "umami_setup_error.png"
                await page.screenshot(path=str(error_path))
                screenshots.append(str(error_path))

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