"""First-run onboarding for the packaged macOS app.

This uses AppleScript dialogs instead of tkinter so the bundled app does not
depend on Tcl/Tk frameworks that are often missing from Homebrew Python builds.
"""

from __future__ import annotations

import subprocess
from os import getenv
from pathlib import Path

import yaml

from hive_compute.app.runtime_config import DEFAULT_COORDINATOR_URL
from hive_compute.app.setup import AppSetupError, enroll_worker_install

_CONFIG_PATH = Path("~/.ambient/config.yaml").expanduser()
_COORDINATOR_URL = DEFAULT_COORDINATOR_URL
_TITLE = "Ambient Setup"


def needs_onboarding() -> bool:
    """True if config is missing or unreadable."""
    if not _CONFIG_PATH.exists():
        return True
    try:
        with open(_CONFIG_PATH) as f:
            data = yaml.safe_load(f) or {}
        return not data.get("coordinator_url") or not data.get("worker_id")
    except Exception:
        return True


def run_onboarding() -> bool:
    """Run the onboarding flow. Returns True if setup completed successfully."""
    if not _show_welcome_dialog():
        return False

    seeded_token = getenv("HIVE_ENROLLMENT_TOKEN", "").strip()
    if seeded_token:
        return _run_token_onboarding(initial_token=seeded_token)

    while True:
        try:
            enroll_worker_install(_COORDINATOR_URL)
        except AppSetupError as exc:
            if exc.code == "invitation_required":
                return _run_token_onboarding()
            if _show_retry_dialog(str(exc)):
                continue
            return False

        _show_ready_dialog()
        return True


def _run_token_onboarding(initial_token: str | None = None) -> bool:
    seeded_token = initial_token or ""
    while True:
        token = seeded_token or _prompt_for_token()
        seeded_token = ""
        if token is None:
            return False

        try:
            enroll_worker_install(_COORDINATOR_URL, token)
        except AppSetupError as exc:
            if _show_retry_dialog(str(exc)):
                continue
            return False

        _show_ready_dialog()
        return True


def _show_welcome_dialog() -> bool:
    output = _run_dialog(
        (
            'set response to display dialog '
            '"Ambient runs in your menu bar and will connect this Mac to the network. '
            'If this deployment still requires an invitation code, Ambient will ask for it next." '
            f'with title "{_TITLE}" buttons {{"Cancel", "Continue"}} default button "Continue"',
            'return "button returned:" & button returned of response',
        )
    )
    return _parse_dialog_output(output).get("button_returned") == "Continue"


def _prompt_for_token() -> str | None:
    while True:
        output = _run_dialog(
            (
                'set response to display dialog "Paste your Ambient invitation code to continue." '
                f'with title "{_TITLE}" default answer "" buttons {{"Cancel", "Join"}} default button "Join"',
                'return "button returned:" & button returned of response '
                '& ", text returned:" & text returned of response',
            )
        )
        result = _parse_dialog_output(output)
        if result.get("button_returned") != "Join":
            return None

        token = result.get("text_returned", "").strip()
        if token:
            return token

        _show_info_dialog("An invitation code is required to join the network.")


def _show_ready_dialog() -> None:
    _show_info_dialog(
        "Ambient is ready.\n\n"
        "The menu bar app will start now. Ambient installs its local worker runtime "
        "and downloads the Whisper model automatically the first time this Mac receives work."
    )


def _show_retry_dialog(message: str) -> bool:
    output = _run_dialog(
        (
            f'set response to display dialog "{_escape_applescript(message)}" '
            f'with title "{_TITLE}" buttons {{"Quit", "Retry"}} default button "Retry"',
            'return "button returned:" & button returned of response',
        )
    )
    return _parse_dialog_output(output).get("button_returned") == "Retry"


def _show_info_dialog(message: str) -> None:
    _run_dialog(
        (
            f'display dialog "{_escape_applescript(message)}" '
            f'with title "{_TITLE}" buttons {{"OK"}} default button "OK"',
        )
    )


def _run_dialog(lines: tuple[str, ...]) -> str:
    result = subprocess.run(
        ["osascript", *sum((["-e", line] for line in lines), [])],
        capture_output=True,
        text=True,
        check=False,
    )
    if result.returncode != 0:
        raise AppSetupError("Ambient could not open the onboarding dialog. Try launching it from Finder again.")
    return result.stdout.strip()


def _parse_dialog_output(output: str) -> dict[str, str]:
    data: dict[str, str] = {}
    for item in output.split(","):
        if ":" not in item:
            continue
        key, value = item.split(":", 1)
        data[key.strip().replace(" ", "_")] = value.strip()
    return data


def _escape_applescript(message: str) -> str:
    return message.replace("\\", "\\\\").replace('"', '\\"')
