"""First-run setup wizard for Proxmox connection configuration."""

from __future__ import annotations

import os
import re
import stat
from dataclasses import dataclass
from pathlib import Path
from typing import Optional

from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical
from textual.screen import Screen
from textual.widgets import (
    Button,
    Footer,
    Header,
    Input,
    Label,
    RadioButton,
    RadioSet,
    Static,
)


@dataclass
class SetupState:
    """State container for setup wizard."""

    # Connection
    proxmox_url: str = "https://pve:8006/api2/json"
    proxmox_node: str = "pve"
    skip_tls_verify: bool = False

    # Authentication
    auth_method: str = "token"  # "token" or "password"
    token_id: str = ""
    token_secret: str = ""
    username: str = "root@pam"
    password: str = ""

    # Storage
    iso_storage_pool: str = "local"
    storage_pool: str = "local-lvm"
    cloudinit_storage_pool: str = "local-lvm"
    network_bridge: str = "vmbr0"


class SetupWizardScreen(Screen):
    """Multi-step wizard for configuring Proxmox connection."""

    BINDINGS = [
        Binding("escape", "cancel", "Cancel", show=True),
    ]

    def __init__(self, from_menu: bool = False) -> None:
        super().__init__()
        self.state = SetupState()
        self.step = 0
        self.total_steps = 5
        self.from_menu = from_menu

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="wizard-container"):
            yield Static("Proxmox Connection Setup", classes="wizard-title")
            yield Static("", id="step-indicator", classes="wizard-step")
            yield Vertical(id="wizard-content", classes="wizard-content")
            with Horizontal(classes="wizard-nav"):
                yield Button("Back", id="back", disabled=True)
                yield Button("Next", id="next", variant="primary")
                yield Button("Cancel", id="cancel")
        yield Footer()

    def on_mount(self) -> None:
        self._load_existing_config()
        self._show_step(0)

    def _output_path(self) -> Path:
        """Return the path where the config file will be written."""
        config_dir = self.app.config.user_config_dir
        if config_dir is None:
            from tui.data import get_user_config_path

            config_dir = get_user_config_path()
        return config_dir / "proxmox.auto.pkrvars.hcl"

    def _load_existing_config(self) -> None:
        """Pre-populate state from existing config file if re-running setup."""
        existing = self.app.script_runner._find_packer_vars()
        if existing is None:
            return
        try:
            content = existing.read_text()
            for line in content.splitlines():
                line = line.strip()
                if not line or line.startswith("#") or "=" not in line:
                    continue
                key, value = line.split("=", 1)
                key = key.strip()
                value = value.strip().strip('"')

                if key == "proxmox_url":
                    self.state.proxmox_url = value
                elif key == "proxmox_node":
                    self.state.proxmox_node = value
                elif key == "proxmox_skip_tls_verify":
                    self.state.skip_tls_verify = value.lower() == "true"
                elif key == "proxmox_token_id":
                    self.state.token_id = value
                    self.state.auth_method = "token"
                elif key == "proxmox_token_secret":
                    self.state.token_secret = value
                elif key == "proxmox_username":
                    self.state.username = value
                    if not self.state.token_id:
                        self.state.auth_method = "password"
                elif key == "proxmox_password":
                    self.state.password = value
                elif key == "iso_storage_pool":
                    self.state.iso_storage_pool = value
                elif key == "storage_pool":
                    self.state.storage_pool = value
                elif key == "cloudinit_storage_pool":
                    self.state.cloudinit_storage_pool = value
                elif key == "network_bridge":
                    self.state.network_bridge = value
        except Exception:
            pass

    def _update_step_indicator(self) -> None:
        """Update the step indicator text."""
        step_names = [
            "Welcome",
            "Connection",
            "Authentication",
            "Storage",
            "Confirm",
        ]
        name = step_names[self.step] if self.step < len(step_names) else "Setup"
        indicator = self.query_one("#step-indicator", Static)
        indicator.update(f"Step {self.step + 1} of {self.total_steps}: {name}")

    def _show_step(self, step: int) -> None:
        """Display a specific wizard step."""
        self.step = step
        self._update_step_indicator()

        content = self.query_one("#wizard-content")
        content.remove_children()

        steps = [
            self._step_welcome,
            self._step_connection,
            self._step_auth,
            self._step_storage,
            self._step_confirm,
        ]

        if 0 <= step < len(steps):
            steps[step](content)

        back_btn = self.query_one("#back", Button)
        next_btn = self.query_one("#next", Button)

        back_btn.disabled = step == 0
        next_btn.label = "Save" if step == len(steps) - 1 else "Next"

        self.set_timer(0.1, self._focus_content)

    def _focus_content(self) -> None:
        """Focus the first interactive widget in the wizard content area."""
        content = self.query_one("#wizard-content")
        for widget_class in (Input, RadioSet):
            try:
                widget = content.query_one(widget_class)
                widget.focus()
                return
            except Exception:
                continue

    def _step_welcome(self, container: Vertical) -> None:
        """Step 1: Welcome and overview."""
        container.mount(Label("Welcome to Proxmox Template Builder Setup"))
        container.mount(
            Static(
                "\nThis wizard will configure your Proxmox API connection.\n\n"
                "You will need:\n"
                "  - Your Proxmox server URL\n"
                "  - The Proxmox node name\n"
                "  - API credentials (token or username/password)\n\n"
                "[dim]Configuration will be saved to:[/dim]\n"
                f"  {self._output_path()}\n\n"
                "[yellow]Note:[/yellow] The file will be created with restricted "
                "permissions (chmod 600)\nsince it contains sensitive credentials.",
                markup=True,
            )
        )

    def _step_connection(self, container: Vertical) -> None:
        """Step 2: Proxmox connection settings."""
        container.mount(Label("Proxmox Server URL:"))
        container.mount(
            Input(
                value=self.state.proxmox_url,
                placeholder="https://pve:8006/api2/json",
                id="proxmox-url",
            )
        )

        container.mount(Label("Proxmox Node Name:"))
        container.mount(
            Input(
                value=self.state.proxmox_node,
                placeholder="pve",
                id="proxmox-node",
            )
        )

        container.mount(Label("Skip TLS Verification:"))
        container.mount(
            RadioSet(
                RadioButton(
                    "No - Verify certificates (Recommended)",
                    id="no",
                    value=not self.state.skip_tls_verify,
                ),
                RadioButton(
                    "Yes - Skip verification (self-signed certs)",
                    id="yes",
                    value=self.state.skip_tls_verify,
                ),
                id="tls-radio",
            )
        )

    def _step_auth(self, container: Vertical) -> None:
        """Step 3: Authentication method and credentials."""
        container.mount(Label("Authentication Method:"))
        container.mount(
            RadioSet(
                RadioButton(
                    "API Token (Recommended)",
                    id="token",
                    value=self.state.auth_method == "token",
                ),
                RadioButton(
                    "Username / Password",
                    id="password",
                    value=self.state.auth_method == "password",
                ),
                id="auth-method-radio",
            )
        )

        container.mount(Static(""))

        # Auth fields go in a sub-container so we can swap them
        # without re-creating the RadioSet (which causes DuplicateIds).
        auth_fields = Vertical(id="auth-fields")
        container.mount(auth_fields)
        self._mount_auth_fields(auth_fields)

    def _mount_auth_fields(self, container: Vertical) -> None:
        """Mount the credential fields for the current auth method."""
        if self.state.auth_method == "token":
            container.mount(Label("Token ID:"))
            container.mount(
                Input(
                    value=self.state.token_id,
                    placeholder="user@realm!token-name",
                    id="token-id",
                )
            )
            container.mount(Label("Token Secret:"))
            container.mount(
                Input(
                    value=self.state.token_secret,
                    password=True,
                    id="token-secret",
                )
            )
        else:
            container.mount(Label("Username:"))
            container.mount(
                Input(
                    value=self.state.username,
                    placeholder="root@pam",
                    id="username",
                )
            )
            container.mount(Label("Password:"))
            container.mount(
                Input(
                    value=self.state.password,
                    password=True,
                    id="password-input",
                )
            )

    def _step_storage(self, container: Vertical) -> None:
        """Step 4: Storage and network settings."""
        container.mount(Label("Storage & Network Configuration:"))
        container.mount(
            Static(
                "[dim]These defaults work for most Proxmox installations.[/dim]",
                markup=True,
            )
        )

        container.mount(Static(""))
        container.mount(Label("ISO Storage Pool:"))
        container.mount(
            Input(value=self.state.iso_storage_pool, id="iso-storage")
        )

        container.mount(Label("VM Disk Storage Pool:"))
        container.mount(
            Input(value=self.state.storage_pool, id="vm-storage")
        )

        container.mount(Label("Cloud-init Storage Pool:"))
        container.mount(
            Input(value=self.state.cloudinit_storage_pool, id="cloudinit-storage")
        )

        container.mount(Label("Network Bridge:"))
        container.mount(
            Input(value=self.state.network_bridge, id="network-bridge")
        )

    def _step_confirm(self, container: Vertical) -> None:
        """Step 5: Confirmation summary."""
        container.mount(Label("Configuration Summary:", classes="summary-title"))

        summary = Vertical(classes="summary-panel")
        container.mount(summary)

        rows = [
            ("Proxmox URL:", self.state.proxmox_url),
            ("Node:", self.state.proxmox_node),
            ("Skip TLS Verify:", "Yes" if self.state.skip_tls_verify else "No"),
            ("Auth Method:", "API Token" if self.state.auth_method == "token" else "Username/Password"),
        ]

        if self.state.auth_method == "token":
            rows.append(("Token ID:", self.state.token_id))
            rows.append(("Token Secret:", "********"))
        else:
            rows.append(("Username:", self.state.username))
            rows.append(("Password:", "********"))

        rows.extend([
            ("ISO Storage:", self.state.iso_storage_pool),
            ("VM Storage:", self.state.storage_pool),
            ("Cloud-init Storage:", self.state.cloudinit_storage_pool),
            ("Network Bridge:", self.state.network_bridge),
        ])

        for label, value in rows:
            summary.mount(Static(f"  {label:20} {value}"))

        container.mount(
            Static(
                f"\n[dim]File will be written to:[/dim]\n"
                f"  {self._output_path()}\n\n"
                "[yellow]Press 'Save' to write configuration.[/yellow]",
                markup=True,
            )
        )

    def on_radio_set_changed(self, event: RadioSet.Changed) -> None:
        """Handle radio button changes."""
        if event.radio_set.id == "tls-radio":
            self.state.skip_tls_verify = event.pressed.id == "yes"
        elif event.radio_set.id == "auth-method-radio":
            new_method = event.pressed.id
            if new_method != self.state.auth_method:
                # Save current auth fields before switching
                self._collect_auth_fields_silent()
                self.state.auth_method = new_method
                # Only swap the credential fields, not the whole step.
                auth_fields = self.query_one("#auth-fields", Vertical)
                auth_fields.remove_children()
                self._mount_auth_fields(auth_fields)

    def _collect_auth_fields_silent(self) -> None:
        """Collect auth fields without validation (for method switching)."""
        try:
            if self.state.auth_method == "token":
                self.state.token_id = self.query_one("#token-id", Input).value.strip()
                self.state.token_secret = self.query_one("#token-secret", Input).value.strip()
            else:
                self.state.username = self.query_one("#username", Input).value.strip()
                self.state.password = self.query_one("#password-input", Input).value.strip()
        except Exception:
            pass

    def _collect_step_data(self) -> bool:
        """Collect and validate data from current step.

        Returns:
            True if validation passed, False otherwise.
        """
        if self.step == 1:  # Connection
            url = self.query_one("#proxmox-url", Input).value.strip()
            node = self.query_one("#proxmox-node", Input).value.strip()

            if not url:
                self.notify("Proxmox URL is required", severity="error")
                return False
            if not (url.startswith("https://") or url.startswith("http://")):
                self.notify("URL must start with https:// or http://", severity="error")
                return False
            if not url.endswith("/api2/json"):
                self.notify("URL must end with /api2/json", severity="error")
                return False
            if not node or not re.match(r"^[a-zA-Z0-9._-]+$", node):
                self.notify("Invalid node name", severity="error")
                return False

            self.state.proxmox_url = url
            self.state.proxmox_node = node

        elif self.step == 2:  # Auth
            if self.state.auth_method == "token":
                token_id = self.query_one("#token-id", Input).value.strip()
                token_secret = self.query_one("#token-secret", Input).value.strip()
                if not token_id:
                    self.notify("Token ID is required", severity="error")
                    return False
                if not token_secret:
                    self.notify("Token Secret is required", severity="error")
                    return False
                self.state.token_id = token_id
                self.state.token_secret = token_secret
            else:
                username = self.query_one("#username", Input).value.strip()
                password = self.query_one("#password-input", Input).value.strip()
                if not username:
                    self.notify("Username is required", severity="error")
                    return False
                if not password:
                    self.notify("Password is required", severity="error")
                    return False
                self.state.username = username
                self.state.password = password

        elif self.step == 3:  # Storage
            fields = [
                ("ISO storage pool", "#iso-storage"),
                ("VM storage pool", "#vm-storage"),
                ("Cloud-init storage pool", "#cloudinit-storage"),
                ("Network bridge", "#network-bridge"),
            ]
            for name, widget_id in fields:
                val = self.query_one(widget_id, Input).value.strip()
                if not val or not re.match(r"^[a-zA-Z0-9._-]+$", val):
                    self.notify(f"Invalid {name}", severity="error")
                    return False

            self.state.iso_storage_pool = self.query_one("#iso-storage", Input).value.strip()
            self.state.storage_pool = self.query_one("#vm-storage", Input).value.strip()
            self.state.cloudinit_storage_pool = self.query_one("#cloudinit-storage", Input).value.strip()
            self.state.network_bridge = self.query_one("#network-bridge", Input).value.strip()

        return True

    def _advance_step(self) -> None:
        """Advance to next step."""
        if not self._collect_step_data():
            return

        if self.step < self.total_steps - 1:
            self._show_step(self.step + 1)
        else:
            self._finish_setup()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle button presses."""
        if event.button.id == "back":
            if self.step > 0:
                self._show_step(self.step - 1)
        elif event.button.id == "next":
            self._advance_step()
        elif event.button.id == "cancel":
            self.action_cancel()

    def action_cancel(self) -> None:
        """Cancel setup."""
        if self.from_menu:
            self.app.pop_screen()
        else:
            from tui.widgets.dialogs import ConfirmDialog

            async def handle_confirm(confirmed: bool) -> None:
                if confirmed:
                    self.app.pop_screen()
                    from tui.screens.main_menu import MainMenuScreen

                    self.app.push_screen(MainMenuScreen())

            self.app.push_screen(
                ConfirmDialog(
                    "Skip Setup?",
                    "Without Proxmox credentials, you won't be able\n"
                    "to build templates.\n\n"
                    "You can run setup later from the main menu.\n\n"
                    "Skip setup and continue?",
                    yes_label="Skip",
                    no_label="Go Back",
                ),
                handle_confirm,
            )

    def _finish_setup(self) -> None:
        """Write config and navigate to main menu."""
        try:
            write_packer_vars(self.state, self._output_path())
        except Exception as e:
            self.notify(f"Failed to write config: {e}", severity="error")
            return

        self.notify(
            f"Configuration saved to {self._output_path()}",
            severity="information",
        )

        if self.from_menu:
            self.app.pop_screen()
        else:
            self.app.pop_screen()
            from tui.screens.main_menu import MainMenuScreen

            self.app.push_screen(MainMenuScreen())


def _hcl_escape(value: str) -> str:
    """Escape a string for HCL double-quoted string literal."""
    return value.replace("\\", "\\\\").replace('"', '\\"')


def write_packer_vars(state: SetupState, output_path: Path) -> None:
    """Write proxmox.auto.pkrvars.hcl from setup state.

    Args:
        state: Setup wizard state with all configuration values.
        output_path: Path to write the file to.
    """
    lines = [
        "# Proxmox Connection Configuration",
        "# Generated by proxmox-template-builder setup wizard",
        "",
        "# Proxmox server details",
        f'proxmox_url  = "{_hcl_escape(state.proxmox_url)}"',
        f'proxmox_node = "{_hcl_escape(state.proxmox_node)}"',
        "",
    ]

    if state.auth_method == "token":
        lines.extend([
            "# Authentication (API Token)",
            f'proxmox_token_id     = "{_hcl_escape(state.token_id)}"',
            f'proxmox_token_secret = "{_hcl_escape(state.token_secret)}"',
        ])
    else:
        lines.extend([
            "# Authentication (Username/Password)",
            f'proxmox_username = "{_hcl_escape(state.username)}"',
            f'proxmox_password = "{_hcl_escape(state.password)}"',
        ])

    lines.extend([
        "",
        "# TLS verification",
        f"proxmox_skip_tls_verify = {'true' if state.skip_tls_verify else 'false'}",
        "",
        "# Storage configuration",
        f'iso_storage_pool       = "{_hcl_escape(state.iso_storage_pool)}"',
        f'storage_pool           = "{_hcl_escape(state.storage_pool)}"',
        f'cloudinit_storage_pool = "{_hcl_escape(state.cloudinit_storage_pool)}"',
        "",
        "# Network configuration",
        f'network_bridge = "{_hcl_escape(state.network_bridge)}"',
        "",
    ])

    content = "\n".join(lines)

    output_path.parent.mkdir(parents=True, exist_ok=True)

    tmp_path = output_path.with_suffix(".tmp")
    try:
        tmp_path.write_text(content)
        os.chmod(tmp_path, stat.S_IRUSR | stat.S_IWUSR)  # 0o600
        tmp_path.rename(output_path)
    except Exception:
        tmp_path.unlink(missing_ok=True)
        raise
