from __future__ import annotations

import os
from pathlib import Path

from textual.app import App, ComposeResult
from textual.containers import Container
from textual.widgets import Footer, Header

from .models.workflow import WorkflowState
from .screens.env_setup import EnvSetupModal, MissingEnvSetupPromptModal
from .screens.login import LoginView
from .screens.wizard import WizardView
from .services.base import ProxmoxService
from .services.factory import ProxmoxServiceFactory
from .settings import ENV_VAR_SPECS, AppSettings, resolve_dotenv_paths, write_config_dotenv
from .terminal_compat import build_driver_class


class PveVmSetupApp(App[None]):
    TITLE = "Proxmox VM Setup"
    SUB_TITLE = "Live-access foundation"

    def __init__(
        self,
        settings: AppSettings,
        *,
        service: ProxmoxService | None = None,
        prompt_for_missing_env_setup: bool | None = None,
        dotenv_path: str | Path = ".env",
        config_dotenv_path: str | Path | None = None,
    ) -> None:
        super().__init__(driver_class=build_driver_class())
        self.settings = settings
        self.workflow = WorkflowState()
        self.service = service or ProxmoxServiceFactory.create(settings)
        self._prompt_for_missing_env_setup = (
            service is None
            if prompt_for_missing_env_setup is None
            else prompt_for_missing_env_setup
        )
        self._dotenv_path = dotenv_path
        self._config_dotenv_path = config_dotenv_path
        self._missing_env_prompted = False

    def compose(self) -> ComposeResult:
        yield Header()
        with Container(id="app-body"):
            yield LoginView(self.settings, self.workflow, self.service)
        yield Footer()

    def on_mount(self) -> None:
        self.call_after_refresh(self._maybe_prompt_for_missing_env_setup)

    def on_unmount(self) -> None:
        close = getattr(self.service, "close", None)
        if callable(close):
            close()

    async def on_login_view_authenticated(self, _: LoginView.Authenticated) -> None:
        self.query_one(LoginView).remove()
        wizard = WizardView(self.settings, self.workflow, self.service)
        await self.query_one("#app-body", Container).mount(wizard)
        wizard.activate()

    def _maybe_prompt_for_missing_env_setup(self) -> None:
        if self._missing_env_prompted or not self._prompt_for_missing_env_setup:
            return
        dotenv_paths = resolve_dotenv_paths(
            dotenv_path=self._dotenv_path,
            config_dotenv_path=self._config_dotenv_path,
        )
        if dotenv_paths.any_exists:
            return
        self._missing_env_prompted = True
        self.push_screen(
            MissingEnvSetupPromptModal(dotenv_paths),
            self._handle_missing_env_prompt_result,
        )

    def _handle_missing_env_prompt_result(self, should_setup: bool | None) -> None:
        if not should_setup:
            return
        self.push_screen(
            EnvSetupModal(self._current_env_values()),
            self._handle_env_setup_result,
        )

    def _handle_env_setup_result(self, values: dict[str, str] | None) -> None:
        if not values:
            return
        write_config_dotenv(values, config_dotenv_path=self._config_dotenv_path)
        self._apply_runtime_env(values)
        self._reload_settings_and_service()

    def _current_env_values(self) -> dict[str, str]:
        return {
            spec.name: os.environ.get(spec.name, "")
            for spec in ENV_VAR_SPECS
            if os.environ.get(spec.name, "")
        }

    def _apply_runtime_env(self, values: dict[str, str]) -> None:
        for spec in ENV_VAR_SPECS:
            if spec.name in values:
                os.environ[spec.name] = values[spec.name]
            else:
                os.environ.pop(spec.name, None)

    def _reload_settings_and_service(self) -> None:
        previous_service = self.service
        self.settings = AppSettings.from_env(
            dotenv_path=self._dotenv_path,
            config_dotenv_path=self._config_dotenv_path,
        )
        self.service = ProxmoxServiceFactory.create(self.settings)
        if self.query(LoginView):
            self.query_one(LoginView).reconfigure(self.settings, self.service)
        if previous_service is not self.service:
            close = getattr(previous_service, "close", None)
            if callable(close):
                close()
