"""VM deployment wizard screen."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional

from textual import work
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,
    OptionList,
    RadioButton,
    RadioSet,
    RichLog,
    SelectionList,
    Static,
)
from textual.widgets.option_list import Option
from textual.widgets.selection_list import Selection


@dataclass
class DeployState:
    """State container for VM deployment wizard."""

    template_id: Optional[int] = None
    template_name: Optional[str] = None
    vm_id: Optional[int] = None
    vm_name: Optional[str] = None
    vm_cores: int = 2
    vm_memory: int = 2048
    vm_disk_size: str = "20G"
    network_mode: str = "dhcp"
    clone_type: str = "linked"
    playbooks: list[str] = field(default_factory=list)


class VMDeployScreen(Screen):
    """Multi-step wizard for deploying VMs from templates."""

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

    def __init__(self) -> None:
        super().__init__()
        self.state = DeployState()
        self.step = 0
        self.total_steps = 5
        self.templates: list[dict] = []

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="wizard-container"):
            yield Static("Deploy VM from Template", 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_templates()

    @work(exclusive=True)
    async def _load_templates(self) -> None:
        """Load templates from Proxmox."""
        self.templates = await self.app.proxmox.get_templates()
        self.app.call_later(self._show_step, 0)

    def _update_step_indicator(self) -> None:
        """Update the step indicator text."""
        step_names = [
            "Select Template",
            "VM Configuration",
            "Network & Clone",
            "Playbooks",
            "Confirm",
        ]
        name = step_names[self.step] if self.step < len(step_names) else "Deploy"
        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_template,
            self._step_vm_config,
            self._step_network_clone,
            self._step_playbooks,
            self._step_confirm,
        ]

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

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

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

    def _step_template(self, container: Vertical) -> None:
        """Step 1: Select template."""
        container.mount(Label("Select Template:"))

        if not self.templates:
            container.mount(
                Static(
                    "[yellow]No templates found.[/yellow]\n"
                    "Build a template first using 'Build New Template'.",
                    markup=True,
                )
            )
            return

        options = []
        for t in self.templates:
            vmid = t.get("vmid", 0)
            name = t.get("name", "unknown")
            options.append(Option(f"{vmid}: {name}", id=str(vmid)))

        container.mount(OptionList(*options, id="template-list"))

    def _step_vm_config(self, container: Vertical) -> None:
        """Step 2: Configure VM settings."""
        # Generate default name with timestamp
        timestamp = datetime.now().strftime("%Y%m%d-%H%M")
        default_name = f"vm-{timestamp}"

        container.mount(Label("VM Configuration:"))

        container.mount(Label("VM Name:"))
        container.mount(
            Input(value=self.state.vm_name or default_name, id="vm-name")
        )

        container.mount(Label("VM ID (leave empty for auto):"))
        container.mount(
            Input(
                value=str(self.state.vm_id) if self.state.vm_id else "",
                placeholder="Auto-assigned",
                id="vm-id",
            )
        )

        container.mount(Label("CPU Cores:"))
        container.mount(Input(value=str(self.state.vm_cores), id="cores"))

        container.mount(Label("Memory (MB):"))
        container.mount(Input(value=str(self.state.vm_memory), id="memory"))

        container.mount(Label("Disk Size:"))
        container.mount(
            RadioSet(
                RadioButton("8G - Minimal", id="8G"),
                RadioButton("20G - Standard", id="20G", value=True),
                RadioButton("40G - Medium", id="40G"),
                RadioButton("60G - Large", id="60G"),
                RadioButton("100G - Extra Large", id="100G"),
                id="disk-radio",
            )
        )

    def _step_network_clone(self, container: Vertical) -> None:
        """Step 3: Network and clone settings."""
        container.mount(Label("Network Configuration:"))
        container.mount(
            RadioSet(
                RadioButton("DHCP - Automatic IP", id="dhcp", value=True),
                RadioButton("Static - Manual IP configuration", id="static"),
                id="network-radio",
            )
        )

        container.mount(Static(""))
        container.mount(Label("Clone Type:"))
        container.mount(
            RadioSet(
                RadioButton(
                    "Linked Clone - Fast, shares base disk with template",
                    id="linked",
                    value=True,
                ),
                RadioButton(
                    "Full Clone - Independent copy, larger but standalone",
                    id="full",
                ),
                id="clone-radio",
            )
        )

        container.mount(
            Static(
                "\n[dim]Linked clones are faster and use less disk space.\n"
                "Full clones are independent and can be moved without the template.[/dim]",
                markup=True,
            )
        )

    def _step_playbooks(self, container: Vertical) -> None:
        """Step 4: Select Ansible playbooks."""
        container.mount(Label("Select Ansible Playbooks (Space to toggle):"))

        playbooks = self.app.script_runner.get_available_playbooks()

        selections = [
            Selection(desc, name, default)
            for name, desc, default in playbooks
        ]

        container.mount(SelectionList(*selections, id="playbook-list"))

        container.mount(
            Static(
                "\n[yellow]Note:[/yellow] Cannot select both 'k3s' and 'k3s-cluster'.\n"
                "MSSQL requires minimum 5GB RAM and 20GB disk.",
                markup=True,
            )
        )

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

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

        rows = [
            ("Template:", f"{self.state.template_id}: {self.state.template_name}"),
            ("VM Name:", self.state.vm_name or "N/A"),
            ("VM ID:", str(self.state.vm_id) if self.state.vm_id else "Auto"),
            ("CPU Cores:", str(self.state.vm_cores)),
            ("Memory:", f"{self.state.vm_memory} MB"),
            ("Disk Size:", self.state.vm_disk_size),
            ("Network:", self.state.network_mode.upper()),
            ("Clone Type:", self.state.clone_type.title()),
            ("Playbooks:", ", ".join(self.state.playbooks) if self.state.playbooks else "None"),
        ]

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

        # Show warnings
        warnings = []
        if "mssql" in self.state.playbooks:
            if self.state.vm_memory < 5120:
                warnings.append("MSSQL requires at least 5GB RAM - will be auto-adjusted")
            disk_num = int(self.state.vm_disk_size.rstrip("G"))
            if disk_num < 20:
                warnings.append("MSSQL requires at least 20GB disk - will be auto-adjusted")

        if warnings:
            container.mount(Static(""))
            for w in warnings:
                container.mount(Static(f"[yellow]Warning: {w}[/yellow]", markup=True))

        container.mount(
            Static(
                "\n[green]Ready to deploy VM.[/green]\n"
                "Press 'Deploy' to start.",
                markup=True,
            )
        )

    def on_option_list_option_selected(
        self, event: OptionList.OptionSelected
    ) -> None:
        """Handle template selection."""
        if event.option_list.id == "template-list":
            template_id = int(event.option.id)
            self.state.template_id = template_id
            # Find template name
            for t in self.templates:
                if t.get("vmid") == template_id:
                    self.state.template_name = t.get("name", "unknown")
                    break
            self._advance_step()

    def on_radio_set_changed(self, event: RadioSet.Changed) -> None:
        """Handle radio button changes."""
        if event.radio_set.id == "disk-radio":
            self.state.vm_disk_size = event.pressed.id
        elif event.radio_set.id == "network-radio":
            self.state.network_mode = event.pressed.id
        elif event.radio_set.id == "clone-radio":
            self.state.clone_type = event.pressed.id

    def _collect_step_data(self) -> bool:
        """Collect data from current step's inputs."""
        if self.step == 1:  # VM config
            try:
                self.state.vm_name = self.query_one("#vm-name", Input).value
                vm_id_str = self.query_one("#vm-id", Input).value
                if vm_id_str:
                    self.state.vm_id = int(vm_id_str)
                self.state.vm_cores = int(self.query_one("#cores", Input).value)
                self.state.vm_memory = int(self.query_one("#memory", Input).value)
            except ValueError:
                self.notify("Invalid number format", severity="error")
                return False

        elif self.step == 3:  # Playbooks
            selection_list = self.query_one("#playbook-list", SelectionList)
            self.state.playbooks = list(selection_list.selected)

            # Validate mutual exclusion
            if "k3s" in self.state.playbooks and "k3s-cluster" in self.state.playbooks:
                self.notify(
                    "Cannot select both k3s and k3s-cluster", severity="error"
                )
                return False

        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._start_deploy()

    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 and return to main menu."""
        self.app.pop_screen()

    def _start_deploy(self) -> None:
        """Start the deployment process."""
        # Auto-adjust for MSSQL
        if "mssql" in self.state.playbooks:
            if self.state.vm_memory < 5120:
                self.state.vm_memory = 5120
            disk_num = int(self.state.vm_disk_size.rstrip("G"))
            if disk_num < 20:
                self.state.vm_disk_size = "20G"

        self.app.push_screen(DeployProgressScreen(self.state))


class DeployProgressScreen(Screen):
    """Screen showing deployment progress."""

    BINDINGS = [
        Binding("escape", "back", "Back (when complete)", show=True),
    ]

    def __init__(self, state: DeployState) -> None:
        super().__init__()
        self.state = state
        self.deploy_complete = False
        self.deploy_success = False

    def compose(self) -> ComposeResult:
        yield Header()
        with Vertical(classes="progress-container"):
            yield Static(f"Deploying: {self.state.vm_name}", classes="progress-title")
            yield RichLog(id="output", classes="progress-output", highlight=True)
            with Horizontal(classes="wizard-nav"):
                yield Button("Close", id="close", disabled=True)
        yield Footer()

    def on_mount(self) -> None:
        self.run_deploy()

    @work(exclusive=True, exit_on_error=False)
    async def run_deploy(self) -> None:
        """Run the deployment."""
        output = self.query_one("#output", RichLog)

        # Get or auto-assign VM ID
        if not self.state.vm_id:
            self.state.vm_id = await self.app.proxmox.find_next_vmid(100)
            self.app.call_later(
                output.write, f"Auto-assigned VM ID: {self.state.vm_id}"
            )

        def on_line(line: str) -> None:
            self.app.call_later(output.write, line)

        self.app.call_later(output.write, "Starting deployment...")
        self.app.call_later(output.write, "")

        # Check if k3s-cluster is selected (special handling)
        if "k3s-cluster" in self.state.playbooks:
            result = await self.app.script_runner.run_deploy_k3s_cluster(
                template_id=self.state.template_id,
                cluster_name=self.state.vm_name,
                cores=self.state.vm_cores,
                memory=self.state.vm_memory,
                disk_size=self.state.vm_disk_size,
                clone_type=self.state.clone_type,
                on_output=on_line,
            )
        else:
            result = await self.app.script_runner.run_deploy_vm(
                template_id=self.state.template_id,
                vm_id=self.state.vm_id,
                vm_name=self.state.vm_name,
                cores=self.state.vm_cores,
                memory=self.state.vm_memory,
                disk_size=self.state.vm_disk_size,
                network_mode=self.state.network_mode,
                clone_type=self.state.clone_type,
                playbooks=self.state.playbooks,
                on_output=on_line,
            )

        self.deploy_complete = True
        self.deploy_success = result == 0

        if result == 0:
            self.app.call_later(output.write, "")
            self.app.call_later(
                output.write, "[green]Deployment completed successfully![/green]"
            )
        else:
            self.app.call_later(output.write, "")
            self.app.call_later(
                output.write, f"[red]Deployment failed with exit code: {result}[/red]"
            )

        self.app.call_later(self._enable_close)

    def _enable_close(self) -> None:
        """Enable the close button."""
        self.query_one("#close", Button).disabled = False

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "close":
            self.app.pop_screen()
            self.app.pop_screen()

    def action_back(self) -> None:
        if self.deploy_complete:
            self.app.pop_screen()
            self.app.pop_screen()
