from __future__ import annotations

from collections.abc import Mapping

from textual import on
from textual.app import ComposeResult
from textual.containers import HorizontalGroup, ScrollableContainer, Vertical
from textual.screen import ModalScreen
from textual.widgets import Button, Input, Static

from ..errors import SettingsError
from ..settings import ENV_VAR_SPECS, AppSettings, DotenvPaths


def _input_id(name: str) -> str:
    return f"env-{name.lower().replace('_', '-')}"


class MissingEnvSetupPromptModal(ModalScreen[bool | None]):
    DEFAULT_CSS = """
    MissingEnvSetupPromptModal {
        align: center middle;
    }

    #missing-env-dialog {
        width: 68;
        max-width: 100%;
        height: auto;
        border: round $accent;
        background: $surface;
        padding: 1 2;
    }

    #missing-env-title {
        text-style: bold;
    }

    #missing-env-actions {
        margin-top: 1;
        height: auto;
        width: 1fr;
        align-horizontal: right;
    }

    #missing-env-actions Button {
        margin-left: 1;
        min-width: 14;
    }
    """

    BINDINGS = [("escape", "cancel", "Skip")]

    def __init__(self, paths: DotenvPaths) -> None:
        super().__init__()
        self._paths = paths

    def compose(self) -> ComposeResult:
        with Vertical(id="missing-env-dialog"):
            yield Static("Set up a .env file?", id="missing-env-title")
            yield Static(
                "No .env file was found in the current directory or the standard config path."
            )
            yield Static(f"Current directory: {self._paths.cwd}")
            yield Static(f"Config file: {self._paths.config}")
            yield Static("PROXMOX_URL is required. All other values may be left blank.")
            with HorizontalGroup(id="missing-env-actions"):
                yield Button("Skip", id="missing-env-skip")
                yield Button("Set Up", id="missing-env-setup", variant="primary")

    def on_mount(self) -> None:
        self.set_focus(self.query_one("#missing-env-setup", Button))

    def action_cancel(self) -> None:
        self.dismiss(False)

    @on(Button.Pressed, "#missing-env-skip")
    def on_skip_pressed(self) -> None:
        self.dismiss(False)

    @on(Button.Pressed, "#missing-env-setup")
    def on_setup_pressed(self) -> None:
        self.dismiss(True)


class EnvSetupModal(ModalScreen[dict[str, str] | None]):
    DEFAULT_CSS = """
    EnvSetupModal {
        align: center middle;
    }

    #env-setup-dialog {
        width: 92;
        max-width: 100%;
        height: 90%;
        border: round $accent;
        background: $surface;
        padding: 1 2;
    }

    #env-setup-title {
        text-style: bold;
        margin-bottom: 1;
    }

    #env-setup-form {
        height: 1fr;
        padding-right: 1;
    }

    .env-label {
        margin-top: 1;
    }

    #env-setup-status {
        margin-top: 1;
        color: $text-muted;
    }

    #env-setup-actions {
        margin-top: 1;
        height: auto;
        width: 1fr;
        align-horizontal: right;
    }

    #env-setup-actions Button {
        margin-left: 1;
        min-width: 14;
    }
    """

    BINDINGS = [("escape", "cancel", "Cancel")]

    def __init__(self, initial_values: Mapping[str, str] | None = None) -> None:
        super().__init__()
        self._initial_values = dict(initial_values or {})

    def compose(self) -> ComposeResult:
        with Vertical(id="env-setup-dialog"):
            yield Static("Create Proxmox Environment File", id="env-setup-title")
            yield Static("Enter values for the supported variables. Leave optional values blank.")
            with ScrollableContainer(id="env-setup-form"):
                for spec in ENV_VAR_SPECS:
                    label = spec.name if not spec.required else f"{spec.name} *"
                    yield Static(label, classes="env-label")
                    yield Input(
                        value=self._initial_values.get(spec.name, ""),
                        placeholder=spec.placeholder,
                        password=spec.secret,
                        id=_input_id(spec.name),
                    )
            yield Static(
                "Values will be saved to ~/.config/pve-vm-setup/.env", id="env-setup-status"
            )
            with HorizontalGroup(id="env-setup-actions"):
                yield Button("Cancel", id="env-setup-cancel")
                yield Button("Save", id="env-setup-save", variant="primary")

    def on_mount(self) -> None:
        self.set_focus(self.query_one(f"#{_input_id('PROXMOX_URL')}", Input))

    def action_cancel(self) -> None:
        self.dismiss(None)

    @on(Button.Pressed, "#env-setup-cancel")
    def on_cancel_pressed(self) -> None:
        self.dismiss(None)

    @on(Button.Pressed, "#env-setup-save")
    def on_save_pressed(self) -> None:
        values = self._collect_values()
        if not values.get("PROXMOX_URL"):
            self._show_status("PROXMOX_URL is required.")
            return
        try:
            AppSettings.from_env(values, load_dotenv_file=False)
        except SettingsError as exc:
            self._show_status(str(exc))
            return
        self.dismiss(values)

    def _collect_values(self) -> dict[str, str]:
        values: dict[str, str] = {}
        for spec in ENV_VAR_SPECS:
            widget = self.query_one(f"#{_input_id(spec.name)}", Input)
            value = widget.value if spec.secret else widget.value.strip()
            if value:
                values[spec.name] = value
        return values

    def _show_status(self, message: str) -> None:
        self.query_one("#env-setup-status", Static).update(message)
