from __future__ import annotations

import iuve_connect_agents.desktop.bootstrap_path  # noqa: F401 — agent root on sys.path

import argparse
import json
import os
from pathlib import Path
import sys

from ..core.config import AgentConfig
from ..core.version import AGENT_MVP_VERSION
from .agent import DesktopAgentMVP


def _default_config_path() -> Path:
    return Path.home() / ".config" / "iuve-connect-agent" / "desktop-config.json"


def _default_state_path() -> Path:
    return Path.home() / ".config" / "iuve-connect-agent" / "desktop-state.json"


def _default_log_path() -> Path:
    return Path.home() / ".config" / "iuve-connect-agent" / "desktop-agent.log"


def _build_default_config_payload(*, backend_base_url: str, app_version: str, update_channel: str) -> dict[str, object]:
    return {
        "agent": {
            "backend_base_url": backend_base_url,
            "device_type": "desktop",
            "app_version": app_version,
            "heartbeat_interval_sec": 30,
            "reconnect_initial_sec": 2,
            "reconnect_max_sec": 60,
            "reconnect_multiplier": 2.0,
            "update_channel": update_channel,
            "signed_bootstrap_required": True,
        },
        "storage_path": str(_default_state_path()),
        "log_path": str(_default_log_path()),
        "tray_ui_enabled": True,
        "settings_ui_enabled": True,
        "update_channel": update_channel,
        "voice_presence": {
            "enabled": False,
            "wake_word_enabled": False,
            "push_to_talk_key": "Ctrl+Shift+Space",
            "locale": "",
            "input_modes": ["push_to_talk", "manual_mic"],
        },
    }


def _write_config_file(config_path: Path, payload: dict[str, object]) -> None:
    config_path.parent.mkdir(parents=True, exist_ok=True)
    config_path.write_text(json.dumps(payload, ensure_ascii=True, indent=2, sort_keys=True), encoding="utf-8")


def _build_cli_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="IuVe Connect Desktop Agent (active controlled candidate)")
    parser.add_argument(
        "command",
        choices=[
            "pair",
            "run",
            "status",
            "upgrade",
            "tray",
            "console",
            "ui",
            "ui-bridge",
            "settings",
            "update-channel",
            "init-config",
            "onboarding",
            "recovery",
            "notifications",
            "scan-debug",
        ],
        help="Desktop command",
    )
    parser.add_argument("--backend", default="", help="Backend base URL")
    parser.add_argument("--config", default=str(_default_config_path()), help="Desktop config JSON path")
    parser.add_argument("--version", default=AGENT_MVP_VERSION, help="Desktop app version")
    parser.add_argument("--pair-token", default="", help="One-time pair token")
    parser.add_argument("--iterations", type=int, default=None, help="Heartbeat loop iterations for test runs")
    parser.add_argument("--update-channel", default="stable", help="Update channel placeholder value")
    parser.add_argument("--dry-run", action="store_true", help="Preview upgrade decision without installation")
    parser.add_argument(
        "--status",
        dest="console_status",
        action="store_true",
        help="Console window/process status (use with console or ui)",
    )
    parser.add_argument(
        "--focus",
        dest="console_focus",
        action="store_true",
        help="Raise existing console window only (use with console or ui)",
    )
    parser.add_argument(
        "--json",
        action="store_true",
        help="Emit JSON for console --status",
    )
    return parser


def _build_agent_from_args(args: argparse.Namespace) -> DesktopAgentMVP:
    config_path = Path(args.config)
    if config_path.exists():
        return DesktopAgentMVP.from_config_file(config_path)

    backend = str(args.backend or "").strip()
    if not backend:
        raise ValueError("backend_or_config_required")

    config = AgentConfig.from_dict(
        {
            "backend_base_url": backend,
            "device_type": "desktop",
            "app_version": args.version,
            "update_channel": args.update_channel,
        }
    )
    return DesktopAgentMVP.create_default(config)


def main(argv: list[str] | None = None) -> int:
    args = _build_cli_parser().parse_args(argv)

    if args.command == "scan-debug":
        from .active.device_capability_scanner import dump_scan_debug

        print(json.dumps(dump_scan_debug(), ensure_ascii=False, indent=2, sort_keys=True))
        return 0

    if args.command == "ui-bridge":
        from .ui_bridge.__main__ import main as ui_bridge_main

        # Preserve --config; optional --open via env IUVE_UI_BRIDGE_OPEN=1
        bridge_argv = ["--config", str(args.config)]
        if str(os.environ.get("IUVE_UI_BRIDGE_OPEN") or "").strip().lower() in {"1", "true", "yes"}:
            bridge_argv.append("--open")
        return ui_bridge_main(bridge_argv)

    if args.command in {"console", "ui"}:
        from .ui.app import run_console, run_console_focus, run_console_status

        if args.console_status:
            return run_console_status(
                config_path=args.config,
                json_output=bool(args.json),
            )
        if args.console_focus:
            return run_console_focus(config_path=args.config)

        return run_console(config_path=args.config)

    if args.command == "init-config":
        backend = str(args.backend or "").strip()
        if not backend:
            print(json.dumps({"ok": False, "error": "backend_required"}, ensure_ascii=True))
            return 2
        config_path = Path(args.config)
        payload = _build_default_config_payload(
            backend_base_url=backend,
            app_version=args.version,
            update_channel=args.update_channel,
        )
        _write_config_file(config_path, payload)
        print(json.dumps({"ok": True, "config_path": str(config_path)}, ensure_ascii=True))
        return 0

    try:
        agent = _build_agent_from_args(args)
    except ValueError as exc:
        print(json.dumps({"ok": False, "error": str(exc)}, ensure_ascii=True))
        return 2

    if args.command == "pair":
        if not args.pair_token.strip():
            print(json.dumps({"ok": False, "error": "pair_token_required"}, ensure_ascii=True))
            return 2
        status = agent.pair_with_token(args.pair_token)
        print(json.dumps({"ok": status == "paired", "status": status}, ensure_ascii=True))
        return 0 if status == "paired" else 1


    if args.command == "run":
        try:
            agent.run_background_loop(iterations=args.iterations)
            print(json.dumps(agent.status_details(), ensure_ascii=True, sort_keys=True))
            return 0
        except Exception as exc:
            # If unpaired or storage error, print clear message and exit 1
            print(json.dumps({"ok": False, "error": f"run failed: {exc}"}, ensure_ascii=True))
            return 1

    if args.command == "status":
        print(json.dumps(agent.status_details(), ensure_ascii=True, sort_keys=True))
        return 0

    if args.command == "upgrade":
        result = agent.upgrade_in_place(dry_run=bool(args.dry_run))
        print(json.dumps(result, ensure_ascii=True, sort_keys=True))
        return 0 if bool(result.get("ok", False)) else 1

    if args.command == "tray":
        print(json.dumps(agent.tray_view_model(), ensure_ascii=True, sort_keys=True))
        return 0

    if args.command == "settings":
        print(json.dumps(agent.settings_screen_placeholder(), ensure_ascii=True, sort_keys=True))
        return 0

    if args.command == "update-channel":
        print(json.dumps(agent.update_channel_placeholder(), ensure_ascii=True, sort_keys=True))
        return 0

    if args.command == "onboarding":
        print(json.dumps(agent.onboarding_wizard_model(), ensure_ascii=True, sort_keys=True))
        return 0

    if args.command == "recovery":
        print(json.dumps(agent.recovery_guidance_model(), ensure_ascii=True, sort_keys=True))
        return 0

    if args.command == "notifications":
        print(json.dumps(agent.notifications_model(), ensure_ascii=True, sort_keys=True))
        return 0

    return 2


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))
