use anyhow::Result;
use bmux_cli_schema::{
    AccessCommand, AuthCommand, Command, ConfigCommand, ConfigProfilesCommand, KeymapCommand,
    KioskCommand, LogsCommand, LogsProfilesCommand, PerfCommand, PlaybookCommand, RecordingCommand,
    RecordingEventKindArg, RemoteCommand, RemoteCompleteCommand, SandboxCommand, SandboxEnvModeArg,
    SandboxSourceArg, SandboxStatusArg, ServerCommand, ServerRecordingCommand, SessionCommand,
    SlotCommand, TerminalCommand,
};
use bmux_config::{BmuxConfig, SandboxCleanupSource};
use bmux_recording_protocol::{RecordingEventKind, RecordingRollingStartOptions};

use super::{
    BuiltInHandlerId, BundleIncludeOptions, BundleSandboxOptions, ConnectionContext,
    InspectTargetOptions, RerunSandboxOptions, RunSandboxOptions, TriageBundleOptions,
    TriageSandboxOptions, built_in_command_by_handler, recording, run_access_add,
    run_access_disable, run_access_enable, run_access_init, run_access_list, run_access_remove,
    run_access_status, run_auth_login, run_auth_logout, run_auth_status, run_client_list,
    run_config_get, run_config_path, run_config_profiles_diff, run_config_profiles_evaluate,
    run_config_profiles_explain, run_config_profiles_lint, run_config_profiles_list,
    run_config_profiles_resolve, run_config_profiles_show, run_config_profiles_switch,
    run_config_set, run_config_show, run_connect, run_doctor, run_external_plugin_command,
    run_follow, run_host, run_hosts, run_join, run_keymap_doctor, run_keymap_explain,
    run_kiosk_attach, run_kiosk_init, run_kiosk_issue_token, run_kiosk_revoke_token,
    run_kiosk_ssh_print_config, run_kiosk_status, run_logs_level, run_logs_path,
    run_logs_profiles_delete, run_logs_profiles_list, run_logs_profiles_rename,
    run_logs_profiles_show, run_logs_tail, run_logs_watch, run_perf_off, run_perf_on,
    run_perf_status, run_playbook_cleanup, run_playbook_diff, run_playbook_dry_run,
    run_playbook_from_recording, run_playbook_interactive, run_playbook_run, run_playbook_validate,
    run_recording_analyze, run_recording_cut, run_recording_delete, run_recording_delete_all,
    run_recording_export, run_recording_inspect, run_recording_list, run_recording_path,
    run_recording_replay, run_recording_start, run_recording_status, run_recording_stop,
    run_recording_verify_smoke, run_remote_complete_sessions, run_remote_complete_targets,
    run_remote_doctor, run_remote_init, run_remote_install_server, run_remote_list,
    run_remote_test, run_remote_upgrade, run_sandbox_bundle, run_sandbox_cleanup,
    run_sandbox_doctor, run_sandbox_inspect, run_sandbox_list, run_sandbox_open,
    run_sandbox_rebuild_index, run_sandbox_rerun, run_sandbox_run, run_sandbox_status,
    run_sandbox_tail, run_sandbox_triage, run_sandbox_verify_bundle, run_server_bridge,
    run_server_gateway, run_server_recording_clear, run_server_recording_path,
    run_server_recording_start, run_server_recording_status, run_server_recording_stop,
    run_server_restore, run_server_save, run_server_start, run_server_status, run_server_stop,
    run_server_whoami_principal, run_session_attach, run_session_detach, run_session_kill,
    run_session_kill_all, run_session_list, run_session_new, run_setup, run_share,
    run_terminal_doctor, run_terminal_install_terminfo, run_unfollow, run_unshare,
};

pub(super) async fn run_command(
    command: &Command,
    connection_context: ConnectionContext<'_>,
) -> Result<u8> {
    match command {
        Command::External(args) => run_external_plugin_command(args).await,
        _ => Box::pin(dispatch_built_in_command(command, connection_context)).await,
    }
}

#[allow(clippy::too_many_lines)]
pub(super) fn built_in_handler_for_command(command: &Command) -> BuiltInHandlerId {
    match command {
        Command::Setup { .. } => BuiltInHandlerId::Setup,
        Command::Host { .. } => BuiltInHandlerId::Host,
        Command::Join { .. } => BuiltInHandlerId::Join,
        Command::Hosts { .. } => BuiltInHandlerId::Hosts,
        Command::Auth { command } => match command {
            AuthCommand::Login { .. } => BuiltInHandlerId::AuthLogin,
            AuthCommand::Status => BuiltInHandlerId::AuthStatus,
            AuthCommand::Logout => BuiltInHandlerId::AuthLogout,
        },
        Command::Access { .. } => BuiltInHandlerId::Access,
        Command::Kiosk { command } => match command {
            KioskCommand::Status { .. } => BuiltInHandlerId::KioskStatus,
            KioskCommand::Init { .. } => BuiltInHandlerId::KioskInit,
            KioskCommand::IssueToken { .. } => BuiltInHandlerId::KioskIssueToken,
            KioskCommand::RevokeToken { .. } => BuiltInHandlerId::KioskRevokeToken,
            KioskCommand::Attach { .. } => BuiltInHandlerId::KioskAttach,
            KioskCommand::SshPrintConfig { .. } => BuiltInHandlerId::KioskSshPrintConfig,
        },
        Command::Share { .. } => BuiltInHandlerId::Share,
        Command::Unshare { .. } => BuiltInHandlerId::Unshare,
        Command::Connect { .. } => BuiltInHandlerId::Connect,
        Command::NewSession { .. } => BuiltInHandlerId::NewSession,
        Command::ListSessions { .. } => BuiltInHandlerId::ListSessions,
        Command::ListClients { .. } => BuiltInHandlerId::ListClients,
        Command::KillSession { .. } => BuiltInHandlerId::KillSession,
        Command::KillAllSessions { .. } => BuiltInHandlerId::KillAllSessions,
        Command::Attach { .. } => BuiltInHandlerId::Attach,
        Command::Detach => BuiltInHandlerId::Detach,
        Command::Follow { .. } => BuiltInHandlerId::Follow,
        Command::Unfollow => BuiltInHandlerId::Unfollow,
        Command::Session { command } => match command {
            SessionCommand::New { .. } => BuiltInHandlerId::SessionNew,
            SessionCommand::List { .. } => BuiltInHandlerId::SessionList,
            SessionCommand::Clients { .. } => BuiltInHandlerId::SessionClients,
            SessionCommand::Kill { .. } => BuiltInHandlerId::SessionKill,
            SessionCommand::KillAll { .. } => BuiltInHandlerId::SessionKillAll,
            SessionCommand::Attach { .. } => BuiltInHandlerId::SessionAttach,
            SessionCommand::Detach => BuiltInHandlerId::SessionDetach,
            SessionCommand::Follow { .. } => BuiltInHandlerId::SessionFollow,
            SessionCommand::Unfollow => BuiltInHandlerId::SessionUnfollow,
        },
        Command::Remote { command } => match command {
            RemoteCommand::List { .. } => BuiltInHandlerId::RemoteList,
            RemoteCommand::Test { .. } => BuiltInHandlerId::RemoteTest,
            RemoteCommand::Doctor { .. } => BuiltInHandlerId::RemoteDoctor,
            RemoteCommand::Init { .. } => BuiltInHandlerId::RemoteInit,
            RemoteCommand::InstallServer { .. } => BuiltInHandlerId::RemoteInstallServer,
            RemoteCommand::Upgrade { .. } => BuiltInHandlerId::RemoteUpgrade,
            RemoteCommand::Complete { command } => match command {
                RemoteCompleteCommand::Targets => BuiltInHandlerId::RemoteCompleteTargets,
                RemoteCompleteCommand::Sessions { .. } => BuiltInHandlerId::RemoteCompleteSessions,
            },
        },
        Command::Server { command } => match command {
            ServerCommand::Start { .. } => BuiltInHandlerId::ServerStart,
            ServerCommand::Status { .. } => BuiltInHandlerId::ServerStatus,
            ServerCommand::WhoamiPrincipal { .. } => BuiltInHandlerId::ServerWhoamiPrincipal,
            ServerCommand::Save => BuiltInHandlerId::ServerSave,
            ServerCommand::Restore { .. } => BuiltInHandlerId::ServerRestore,
            ServerCommand::Stop => BuiltInHandlerId::ServerStop,
            ServerCommand::Recording { command } => match command {
                ServerRecordingCommand::Start { .. } => BuiltInHandlerId::ServerRecordingStart,
                ServerRecordingCommand::Stop => BuiltInHandlerId::ServerRecordingStop,
                ServerRecordingCommand::Status { .. } => BuiltInHandlerId::ServerRecordingStatus,
                ServerRecordingCommand::Path { .. } => BuiltInHandlerId::ServerRecordingPath,
                ServerRecordingCommand::Clear { .. } => BuiltInHandlerId::ServerRecordingClear,
            },
            ServerCommand::Gateway { .. } => BuiltInHandlerId::ServerGateway,
            ServerCommand::Bridge { .. } => BuiltInHandlerId::ServerBridge,
        },
        Command::Logs { command } => match command {
            LogsCommand::Path { .. } => BuiltInHandlerId::LogsPath,
            LogsCommand::Level { .. } => BuiltInHandlerId::LogsLevel,
            LogsCommand::Tail { .. } => BuiltInHandlerId::LogsTail,
            LogsCommand::Watch { .. } => BuiltInHandlerId::LogsWatch,
            LogsCommand::Profiles { command } => match command {
                LogsProfilesCommand::List { .. } => BuiltInHandlerId::LogsProfilesList,
                LogsProfilesCommand::Show { .. } => BuiltInHandlerId::LogsProfilesShow,
                LogsProfilesCommand::Delete { .. } => BuiltInHandlerId::LogsProfilesDelete,
                LogsProfilesCommand::Rename { .. } => BuiltInHandlerId::LogsProfilesRename,
            },
        },
        Command::Config { command } => match command {
            ConfigCommand::Path { .. } => BuiltInHandlerId::ConfigPath,
            ConfigCommand::Show { .. } => BuiltInHandlerId::ConfigShow,
            ConfigCommand::Get { .. } => BuiltInHandlerId::ConfigGet,
            ConfigCommand::Set { .. } => BuiltInHandlerId::ConfigSet,
            ConfigCommand::Profiles { command } => match command {
                ConfigProfilesCommand::List { .. } => BuiltInHandlerId::ConfigProfilesList,
                ConfigProfilesCommand::Show { .. } => BuiltInHandlerId::ConfigProfilesShow,
                ConfigProfilesCommand::Resolve { .. } => BuiltInHandlerId::ConfigProfilesResolve,
                ConfigProfilesCommand::Explain { .. } => BuiltInHandlerId::ConfigProfilesExplain,
                ConfigProfilesCommand::Switch { .. } => BuiltInHandlerId::ConfigProfilesSwitch,
                ConfigProfilesCommand::Diff { .. } => BuiltInHandlerId::ConfigProfilesDiff,
                ConfigProfilesCommand::Lint { .. } => BuiltInHandlerId::ConfigProfilesLint,
                ConfigProfilesCommand::Evaluate { .. } => BuiltInHandlerId::ConfigProfilesEvaluate,
            },
        },
        Command::Perf { command } => match command {
            PerfCommand::Status { .. } => BuiltInHandlerId::PerfStatus,
            PerfCommand::On { .. } => BuiltInHandlerId::PerfOn,
            PerfCommand::Off { .. } => BuiltInHandlerId::PerfOff,
        },
        Command::Doctor { .. } => BuiltInHandlerId::Doctor,
        Command::Keymap { command } => match command {
            KeymapCommand::Doctor { .. } => BuiltInHandlerId::KeymapDoctor,
            KeymapCommand::Explain { .. } => BuiltInHandlerId::KeymapExplain,
        },
        Command::Terminal { command } => match command {
            TerminalCommand::Doctor { .. } => BuiltInHandlerId::TerminalDoctor,
            TerminalCommand::InstallTerminfo { .. } => BuiltInHandlerId::TerminalInstallTerminfo,
        },
        Command::Recording { command } => match command {
            RecordingCommand::Start { .. } => BuiltInHandlerId::RecordingStart,
            RecordingCommand::Stop { .. } => BuiltInHandlerId::RecordingStop,
            RecordingCommand::Status { .. } => BuiltInHandlerId::RecordingStatus,
            RecordingCommand::Path { .. } => BuiltInHandlerId::RecordingPath,
            RecordingCommand::List { .. } => BuiltInHandlerId::RecordingList,
            RecordingCommand::Delete { .. } => BuiltInHandlerId::RecordingDelete,
            RecordingCommand::DeleteAll { .. } => BuiltInHandlerId::RecordingDeleteAll,
            RecordingCommand::Cut { .. } => BuiltInHandlerId::RecordingCut,
            RecordingCommand::Inspect { .. } => BuiltInHandlerId::RecordingInspect,
            RecordingCommand::Analyze { .. } => BuiltInHandlerId::RecordingAnalyze,
            RecordingCommand::Replay { .. } => BuiltInHandlerId::RecordingReplay,
            RecordingCommand::VerifySmoke { .. } => BuiltInHandlerId::RecordingVerifySmoke,
            RecordingCommand::Export { .. } => BuiltInHandlerId::RecordingExport,
            RecordingCommand::Prune { .. } => BuiltInHandlerId::RecordingPrune,
        },
        Command::Playbook { command } => match command {
            PlaybookCommand::Run { .. } => BuiltInHandlerId::PlaybookRun,
            PlaybookCommand::Validate { .. } => BuiltInHandlerId::PlaybookValidate,
            PlaybookCommand::Interactive { .. } => BuiltInHandlerId::PlaybookInteractive,
            PlaybookCommand::FromRecording { .. } => BuiltInHandlerId::PlaybookFromRecording,
            PlaybookCommand::DryRun { .. } => BuiltInHandlerId::PlaybookDryRun,
            PlaybookCommand::Diff { .. } => BuiltInHandlerId::PlaybookDiff,
            PlaybookCommand::Cleanup { .. } => BuiltInHandlerId::PlaybookCleanup,
        },
        Command::Sandbox { command } => match command {
            SandboxCommand::Dev { .. } => BuiltInHandlerId::SandboxDev,
            SandboxCommand::Run { .. } => BuiltInHandlerId::SandboxRun,
            SandboxCommand::List { .. } => BuiltInHandlerId::SandboxList,
            SandboxCommand::Status { .. } => BuiltInHandlerId::SandboxStatus,
            SandboxCommand::Inspect { .. } => BuiltInHandlerId::SandboxInspect,
            SandboxCommand::Tail { .. } => BuiltInHandlerId::SandboxTail,
            SandboxCommand::Open { .. } => BuiltInHandlerId::SandboxOpen,
            SandboxCommand::Rerun { .. } => BuiltInHandlerId::SandboxRerun,
            SandboxCommand::Triage { .. } => BuiltInHandlerId::SandboxTriage,
            SandboxCommand::Doctor { .. } => BuiltInHandlerId::SandboxDoctor,
            SandboxCommand::Bundle { .. } => BuiltInHandlerId::SandboxBundle,
            SandboxCommand::VerifyBundle { .. } => BuiltInHandlerId::SandboxVerifyBundle,
            SandboxCommand::Cleanup { .. } => BuiltInHandlerId::SandboxCleanup,
            SandboxCommand::Clean { .. } => BuiltInHandlerId::SandboxClean,
            SandboxCommand::RebuildIndex { .. } => BuiltInHandlerId::SandboxRebuildIndex,
        },
        Command::Slot { command } | Command::Env { command } => match command {
            SlotCommand::List { .. } => BuiltInHandlerId::SlotList,
            SlotCommand::Show { .. } => BuiltInHandlerId::SlotShow,
            SlotCommand::Paths { .. } => BuiltInHandlerId::SlotPaths,
            SlotCommand::Doctor => BuiltInHandlerId::SlotDoctor,
            SlotCommand::Install { .. } => BuiltInHandlerId::SlotInstall,
            SlotCommand::Uninstall { .. } => BuiltInHandlerId::SlotUninstall,
            SlotCommand::Shell { .. } => BuiltInHandlerId::SlotShell,
            SlotCommand::Exec { .. } => BuiltInHandlerId::SlotExec,
            SlotCommand::Print { .. } => BuiltInHandlerId::SlotPrint,
        },
        Command::External(_) => unreachable!("external commands are dispatched separately"),
    }
}

#[allow(
    clippy::match_same_arms,
    clippy::too_many_lines,
    clippy::large_stack_frames
)] // Short aliases and full subcommand forms dispatch to the same function by design
pub(super) async fn dispatch_built_in_command(
    command: &Command,
    connection_context: ConnectionContext<'_>,
) -> Result<u8> {
    let handler = built_in_handler_for_command(command);
    let _descriptor = built_in_command_by_handler(handler);
    match (handler, command) {
        (BuiltInHandlerId::Setup, Command::Setup { check, mode }) => run_setup(*check, *mode).await,
        (
            BuiltInHandlerId::Host,
            Command::Host {
                listen,
                name,
                copy,
                daemon,
                status,
                stop,
                restart,
                mode,
            },
        ) => {
            run_host(
                listen,
                name.as_deref(),
                *copy,
                *daemon,
                *status,
                *stop,
                *restart,
                *mode,
                false,
            )
            .await
        }
        (BuiltInHandlerId::Join, Command::Join { link, session }) => {
            Box::pin(run_join(link.as_deref(), session.as_deref())).await
        }
        (BuiltInHandlerId::Hosts, Command::Hosts { verbose }) => run_hosts(*verbose),
        (
            BuiltInHandlerId::AuthLogin,
            Command::Auth {
                command: AuthCommand::Login { no_browser },
            },
        ) => run_auth_login(*no_browser).await,
        (
            BuiltInHandlerId::AuthStatus,
            Command::Auth {
                command: AuthCommand::Status,
            },
        ) => run_auth_status(),
        (
            BuiltInHandlerId::AuthLogout,
            Command::Auth {
                command: AuthCommand::Logout,
            },
        ) => run_auth_logout(),
        (
            BuiltInHandlerId::Access,
            Command::Access {
                command: AccessCommand::Status,
            },
        ) => run_access_status(),
        (
            BuiltInHandlerId::Access,
            Command::Access {
                command:
                    AccessCommand::Init {
                        agent,
                        key_file,
                        public_key,
                        github_user,
                        yes,
                    },
            },
        ) => run_access_init(*agent, key_file, public_key, github_user, *yes),
        (
            BuiltInHandlerId::Access,
            Command::Access {
                command:
                    AccessCommand::Add {
                        agent,
                        key_file,
                        public_key,
                        github_user,
                    },
            },
        ) => run_access_add(*agent, key_file, public_key, github_user),
        (
            BuiltInHandlerId::Access,
            Command::Access {
                command: AccessCommand::List { json },
            },
        ) => run_access_list(*json),
        (
            BuiltInHandlerId::Access,
            Command::Access {
                command: AccessCommand::Remove { fingerprint, yes },
            },
        ) => run_access_remove(fingerprint, *yes),
        (
            BuiltInHandlerId::Access,
            Command::Access {
                command: AccessCommand::Enable,
            },
        ) => run_access_enable(),
        (
            BuiltInHandlerId::Access,
            Command::Access {
                command: AccessCommand::Disable,
            },
        ) => run_access_disable(),
        (
            BuiltInHandlerId::KioskStatus,
            Command::Kiosk {
                command: KioskCommand::Status { json },
            },
        ) => run_kiosk_status(*json),
        (
            BuiltInHandlerId::KioskInit,
            Command::Kiosk {
                command:
                    KioskCommand::Init {
                        profile,
                        all_profiles,
                        dry_run,
                        yes,
                    },
            },
        ) => run_kiosk_init(profile, *all_profiles, *dry_run, *yes),
        (
            BuiltInHandlerId::KioskIssueToken,
            Command::Kiosk {
                command:
                    KioskCommand::IssueToken {
                        profile,
                        session,
                        ttl_secs,
                        one_shot,
                        multi_use,
                    },
            },
        ) => run_kiosk_issue_token(
            profile,
            session.as_deref(),
            *ttl_secs,
            *one_shot,
            *multi_use,
        ),
        (
            BuiltInHandlerId::KioskRevokeToken,
            Command::Kiosk {
                command: KioskCommand::RevokeToken { token_id },
            },
        ) => run_kiosk_revoke_token(token_id),
        (
            BuiltInHandlerId::KioskAttach,
            Command::Kiosk {
                command: KioskCommand::Attach { profile, token },
            },
        ) => run_kiosk_attach(profile, token, connection_context).await,
        (
            BuiltInHandlerId::KioskSshPrintConfig,
            Command::Kiosk {
                command:
                    KioskCommand::SshPrintConfig {
                        profile,
                        all_profiles,
                    },
            },
        ) => run_kiosk_ssh_print_config(profile, *all_profiles),
        (
            BuiltInHandlerId::Share,
            Command::Share {
                target,
                secondary,
                name,
                role,
                ttl,
                one_time,
                copy,
                qr,
            },
        ) => {
            run_share(
                target.as_deref(),
                secondary.as_deref(),
                name.as_deref(),
                role,
                ttl.as_deref(),
                *one_time,
                *copy,
                *qr,
            )
            .await
        }
        (BuiltInHandlerId::Unshare, Command::Unshare { name }) => run_unshare(name).await,
        (
            BuiltInHandlerId::Connect,
            Command::Connect {
                target,
                session,
                follow,
                global,
                reconnect_forever,
            },
        ) => {
            run_connect(
                target.as_deref(),
                session.as_deref(),
                follow.as_deref(),
                *global,
                *reconnect_forever,
            )
            .await
        }
        (BuiltInHandlerId::NewSession, Command::NewSession { name }) => {
            run_session_new(name.clone(), connection_context).await
        }
        (BuiltInHandlerId::ListSessions, Command::ListSessions { json }) => {
            run_session_list(*json, connection_context).await
        }
        (BuiltInHandlerId::ListClients, Command::ListClients { json }) => {
            run_client_list(*json, connection_context).await
        }
        (
            BuiltInHandlerId::KillSession,
            Command::KillSession {
                target,
                force_local,
            },
        ) => run_session_kill(target, *force_local, connection_context).await,
        (BuiltInHandlerId::KillAllSessions, Command::KillAllSessions { force_local }) => {
            run_session_kill_all(*force_local, connection_context).await
        }
        (
            BuiltInHandlerId::Attach,
            Command::Attach {
                target,
                follow,
                global,
            },
        ) => {
            run_session_attach(
                target.as_deref(),
                follow.as_deref(),
                *global,
                connection_context,
            )
            .await
        }
        (BuiltInHandlerId::Detach, Command::Detach) => run_session_detach(connection_context).await,
        (
            BuiltInHandlerId::Follow,
            Command::Follow {
                target_client_id,
                global,
            },
        ) => run_follow(target_client_id, *global, connection_context).await,
        (BuiltInHandlerId::Unfollow, Command::Unfollow) => run_unfollow(connection_context).await,
        (
            BuiltInHandlerId::SessionNew,
            Command::Session {
                command: SessionCommand::New { name },
            },
        ) => run_session_new(name.clone(), connection_context).await,
        (
            BuiltInHandlerId::SessionList,
            Command::Session {
                command: SessionCommand::List { json },
            },
        ) => run_session_list(*json, connection_context).await,
        (
            BuiltInHandlerId::SessionClients,
            Command::Session {
                command: SessionCommand::Clients { json },
            },
        ) => run_client_list(*json, connection_context).await,
        (
            BuiltInHandlerId::SessionKill,
            Command::Session {
                command:
                    SessionCommand::Kill {
                        target,
                        force_local,
                    },
            },
        ) => run_session_kill(target, *force_local, connection_context).await,
        (
            BuiltInHandlerId::SessionKillAll,
            Command::Session {
                command: SessionCommand::KillAll { force_local },
            },
        ) => run_session_kill_all(*force_local, connection_context).await,
        (
            BuiltInHandlerId::SessionAttach,
            Command::Session {
                command:
                    SessionCommand::Attach {
                        target,
                        follow,
                        global,
                    },
            },
        ) => {
            run_session_attach(
                target.as_deref(),
                follow.as_deref(),
                *global,
                connection_context,
            )
            .await
        }
        (
            BuiltInHandlerId::SessionDetach,
            Command::Session {
                command: SessionCommand::Detach,
            },
        ) => run_session_detach(connection_context).await,
        (
            BuiltInHandlerId::SessionFollow,
            Command::Session {
                command:
                    SessionCommand::Follow {
                        target_client_id,
                        global,
                    },
            },
        ) => run_follow(target_client_id, *global, connection_context).await,
        (
            BuiltInHandlerId::SessionUnfollow,
            Command::Session {
                command: SessionCommand::Unfollow,
            },
        ) => run_unfollow(connection_context).await,
        (
            BuiltInHandlerId::RemoteList,
            Command::Remote {
                command: RemoteCommand::List { json },
            },
        ) => run_remote_list(*json),
        (
            BuiltInHandlerId::RemoteTest,
            Command::Remote {
                command: RemoteCommand::Test { target },
            },
        ) => run_remote_test(target).await,
        (
            BuiltInHandlerId::RemoteDoctor,
            Command::Remote {
                command: RemoteCommand::Doctor { target, fix },
            },
        ) => run_remote_doctor(target, *fix).await,
        (
            BuiltInHandlerId::RemoteInit,
            Command::Remote {
                command:
                    RemoteCommand::Init {
                        name,
                        ssh,
                        tls,
                        iroh,
                        user,
                        port,
                        set_default,
                    },
            },
        ) => {
            run_remote_init(
                name,
                ssh.as_deref(),
                tls.as_deref(),
                iroh.as_deref(),
                user.as_deref(),
                *port,
                *set_default,
            )
            .await
        }
        (
            BuiltInHandlerId::RemoteInstallServer,
            Command::Remote {
                command: RemoteCommand::InstallServer { target },
            },
        ) => run_remote_install_server(target).await,
        (
            BuiltInHandlerId::RemoteUpgrade,
            Command::Remote {
                command: RemoteCommand::Upgrade { target },
            },
        ) => run_remote_upgrade(target.as_deref()).await,
        (
            BuiltInHandlerId::RemoteCompleteTargets,
            Command::Remote {
                command:
                    RemoteCommand::Complete {
                        command: RemoteCompleteCommand::Targets,
                    },
            },
        ) => run_remote_complete_targets(),
        (
            BuiltInHandlerId::RemoteCompleteSessions,
            Command::Remote {
                command:
                    RemoteCommand::Complete {
                        command: RemoteCompleteCommand::Sessions { target },
                    },
            },
        ) => run_remote_complete_sessions(target).await,
        (
            BuiltInHandlerId::ServerStart,
            Command::Server {
                command:
                    ServerCommand::Start {
                        daemon,
                        foreground_internal,
                        pane_shell_integration,
                        no_pane_shell_integration,
                        rolling_recording,
                        no_rolling_recording,
                        rolling_window_secs,
                        rolling_event_kind_all,
                        rolling_event_kind,
                        rolling_capture_input,
                        no_rolling_capture_input,
                        rolling_capture_output,
                        no_rolling_capture_output,
                        rolling_capture_events,
                        no_rolling_capture_events,
                        rolling_capture_protocol_replies,
                        no_rolling_capture_protocol_replies,
                        rolling_capture_images,
                        no_rolling_capture_images,
                    },
            },
        ) => {
            let rolling_enabled_override = if *rolling_recording {
                Some(true)
            } else if *no_rolling_recording {
                Some(false)
            } else {
                None
            };
            let pane_shell_integration_override =
                bool_override(*pane_shell_integration, *no_pane_shell_integration);
            let rolling_options = RecordingRollingStartOptions {
                window_secs: *rolling_window_secs,
                name: None,
                event_kinds: if *rolling_event_kind_all {
                    Some(all_recording_event_kinds())
                } else if rolling_event_kind.is_empty() {
                    None
                } else {
                    Some(
                        rolling_event_kind
                            .iter()
                            .copied()
                            .map(recording_event_kind_arg_to_ipc)
                            .collect(),
                    )
                },
                capture_input: bool_override(*rolling_capture_input, *no_rolling_capture_input),
                capture_output: bool_override(*rolling_capture_output, *no_rolling_capture_output),
                capture_events: bool_override(*rolling_capture_events, *no_rolling_capture_events),
                capture_protocol_replies: bool_override(
                    *rolling_capture_protocol_replies,
                    *no_rolling_capture_protocol_replies,
                ),
                capture_images: bool_override(*rolling_capture_images, *no_rolling_capture_images),
            };
            run_server_start(
                *daemon,
                *foreground_internal,
                rolling_enabled_override,
                rolling_options,
                pane_shell_integration_override,
                None,
            )
            .await
        }
        (
            BuiltInHandlerId::ServerStatus,
            Command::Server {
                command: ServerCommand::Status { json },
            },
        ) => run_server_status(*json, connection_context).await,
        (
            BuiltInHandlerId::ServerWhoamiPrincipal,
            Command::Server {
                command: ServerCommand::WhoamiPrincipal { json },
            },
        ) => run_server_whoami_principal(*json, connection_context).await,
        (
            BuiltInHandlerId::ServerSave,
            Command::Server {
                command: ServerCommand::Save,
            },
        ) => run_server_save(connection_context).await,
        (
            BuiltInHandlerId::ServerRestore,
            Command::Server {
                command: ServerCommand::Restore { dry_run, yes },
            },
        ) => run_server_restore(*dry_run, *yes, connection_context).await,
        (
            BuiltInHandlerId::ServerStop,
            Command::Server {
                command: ServerCommand::Stop,
            },
        ) => run_server_stop(connection_context).await,
        (
            BuiltInHandlerId::ServerRecordingStart,
            Command::Server {
                command:
                    ServerCommand::Recording {
                        command:
                            ServerRecordingCommand::Start {
                                rolling_window_secs,
                                name,
                                rolling_event_kind_all,
                                rolling_event_kind,
                                rolling_capture_input,
                                no_rolling_capture_input,
                                rolling_capture_output,
                                no_rolling_capture_output,
                                rolling_capture_events,
                                no_rolling_capture_events,
                                rolling_capture_protocol_replies,
                                no_rolling_capture_protocol_replies,
                                rolling_capture_images,
                                no_rolling_capture_images,
                            },
                    },
            },
        ) => {
            run_server_recording_start(
                RecordingRollingStartOptions {
                    window_secs: *rolling_window_secs,
                    name: name.clone(),
                    event_kinds: if *rolling_event_kind_all {
                        Some(all_recording_event_kinds())
                    } else if rolling_event_kind.is_empty() {
                        None
                    } else {
                        Some(
                            rolling_event_kind
                                .iter()
                                .copied()
                                .map(recording_event_kind_arg_to_ipc)
                                .collect(),
                        )
                    },
                    capture_input: bool_override(*rolling_capture_input, *no_rolling_capture_input),
                    capture_output: bool_override(
                        *rolling_capture_output,
                        *no_rolling_capture_output,
                    ),
                    capture_events: bool_override(
                        *rolling_capture_events,
                        *no_rolling_capture_events,
                    ),
                    capture_protocol_replies: bool_override(
                        *rolling_capture_protocol_replies,
                        *no_rolling_capture_protocol_replies,
                    ),
                    capture_images: bool_override(
                        *rolling_capture_images,
                        *no_rolling_capture_images,
                    ),
                },
                connection_context,
            )
            .await
        }
        (
            BuiltInHandlerId::ServerRecordingStop,
            Command::Server {
                command:
                    ServerCommand::Recording {
                        command: ServerRecordingCommand::Stop,
                    },
            },
        ) => run_server_recording_stop(connection_context).await,
        (
            BuiltInHandlerId::ServerRecordingStatus,
            Command::Server {
                command:
                    ServerCommand::Recording {
                        command: ServerRecordingCommand::Status { json },
                    },
            },
        ) => run_server_recording_status(*json, connection_context).await,
        (
            BuiltInHandlerId::ServerRecordingPath,
            Command::Server {
                command:
                    ServerCommand::Recording {
                        command: ServerRecordingCommand::Path { json },
                    },
            },
        ) => run_server_recording_path(*json, connection_context).await,
        (
            BuiltInHandlerId::ServerRecordingClear,
            Command::Server {
                command:
                    ServerCommand::Recording {
                        command: ServerRecordingCommand::Clear { json, no_restart },
                    },
            },
        ) => run_server_recording_clear(*json, *no_restart, connection_context).await,
        (
            BuiltInHandlerId::ServerGateway,
            Command::Server {
                command:
                    ServerCommand::Gateway {
                        listen,
                        host,
                        host_mode,
                        host_relay,
                        quick,
                        cert_file,
                        key_file,
                    },
            },
        ) => {
            run_server_gateway(
                listen,
                *host,
                *host_mode,
                host_relay,
                *quick,
                cert_file.as_deref(),
                key_file.as_deref(),
            )
            .await
        }
        (
            BuiltInHandlerId::ServerBridge,
            Command::Server {
                command: ServerCommand::Bridge { stdio, preflight },
            },
        ) => run_server_bridge(*stdio, *preflight).await,
        (
            BuiltInHandlerId::LogsPath,
            Command::Logs {
                command: LogsCommand::Path { json },
            },
        ) => run_logs_path(*json),
        (
            BuiltInHandlerId::LogsLevel,
            Command::Logs {
                command: LogsCommand::Level { json },
            },
        ) => run_logs_level(*json),
        (
            BuiltInHandlerId::LogsTail,
            Command::Logs {
                command:
                    LogsCommand::Tail {
                        lines,
                        since,
                        no_follow,
                    },
            },
        ) => run_logs_tail(*lines, since.as_deref(), !*no_follow),
        (
            BuiltInHandlerId::LogsWatch,
            Command::Logs {
                command:
                    LogsCommand::Watch {
                        lines,
                        since,
                        profile,
                        include,
                        include_i,
                        exclude,
                        exclude_i,
                    },
            },
        ) => run_logs_watch(
            *lines,
            since.as_deref(),
            profile.as_deref(),
            include,
            include_i,
            exclude,
            exclude_i,
        ),
        (
            BuiltInHandlerId::LogsProfilesList,
            Command::Logs {
                command:
                    LogsCommand::Profiles {
                        command: LogsProfilesCommand::List { json },
                    },
            },
        ) => run_logs_profiles_list(*json),
        (
            BuiltInHandlerId::LogsProfilesShow,
            Command::Logs {
                command:
                    LogsCommand::Profiles {
                        command: LogsProfilesCommand::Show { profile, json },
                    },
            },
        ) => run_logs_profiles_show(profile.as_deref(), *json),
        (
            BuiltInHandlerId::LogsProfilesDelete,
            Command::Logs {
                command:
                    LogsCommand::Profiles {
                        command: LogsProfilesCommand::Delete { profile },
                    },
            },
        ) => run_logs_profiles_delete(profile),
        (
            BuiltInHandlerId::LogsProfilesRename,
            Command::Logs {
                command:
                    LogsCommand::Profiles {
                        command: LogsProfilesCommand::Rename { from, to },
                    },
            },
        ) => run_logs_profiles_rename(from, to),
        (
            BuiltInHandlerId::ConfigPath,
            Command::Config {
                command: ConfigCommand::Path { json },
            },
        ) => run_config_path(*json),
        (
            BuiltInHandlerId::ConfigShow,
            Command::Config {
                command: ConfigCommand::Show { json },
            },
        ) => run_config_show(*json),
        (
            BuiltInHandlerId::ConfigGet,
            Command::Config {
                command: ConfigCommand::Get { key, json },
            },
        ) => run_config_get(key, *json),
        (
            BuiltInHandlerId::ConfigSet,
            Command::Config {
                command: ConfigCommand::Set { key, value },
            },
        ) => run_config_set(key, value),
        (
            BuiltInHandlerId::ConfigProfilesList,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command: ConfigProfilesCommand::List { json },
                    },
            },
        ) => run_config_profiles_list(*json),
        (
            BuiltInHandlerId::ConfigProfilesShow,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command: ConfigProfilesCommand::Show { profile, json },
                    },
            },
        ) => run_config_profiles_show(profile, *json),
        (
            BuiltInHandlerId::ConfigProfilesResolve,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command: ConfigProfilesCommand::Resolve { profile, json },
                    },
            },
        ) => run_config_profiles_resolve(profile.as_deref(), *json),
        (
            BuiltInHandlerId::ConfigProfilesExplain,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command: ConfigProfilesCommand::Explain { profile, json },
                    },
            },
        ) => run_config_profiles_explain(profile.as_deref(), *json),
        (
            BuiltInHandlerId::ConfigProfilesSwitch,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command:
                            ConfigProfilesCommand::Switch {
                                profile,
                                dry_run,
                                json,
                            },
                    },
            },
        ) => run_config_profiles_switch(profile, *dry_run, *json),
        (
            BuiltInHandlerId::ConfigProfilesDiff,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command: ConfigProfilesCommand::Diff { from, to, json },
                    },
            },
        ) => run_config_profiles_diff(from, to, *json),
        (
            BuiltInHandlerId::ConfigProfilesLint,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command: ConfigProfilesCommand::Lint { json },
                    },
            },
        ) => run_config_profiles_lint(*json),
        (
            BuiltInHandlerId::ConfigProfilesEvaluate,
            Command::Config {
                command:
                    ConfigCommand::Profiles {
                        command: ConfigProfilesCommand::Evaluate { json },
                    },
            },
        ) => run_config_profiles_evaluate(*json),
        (
            BuiltInHandlerId::PerfStatus,
            Command::Perf {
                command: PerfCommand::Status { json },
            },
        ) => run_perf_status(*json, connection_context).await,
        (
            BuiltInHandlerId::PerfOn,
            Command::Perf {
                command: PerfCommand::On { profile, json },
            },
        ) => run_perf_on(*profile, *json, connection_context).await,
        (
            BuiltInHandlerId::PerfOff,
            Command::Perf {
                command: PerfCommand::Off { json },
            },
        ) => run_perf_off(*json, connection_context).await,
        (BuiltInHandlerId::Doctor, Command::Doctor { json, hosted }) => {
            run_doctor(*json, *hosted).await
        }
        (
            BuiltInHandlerId::KeymapDoctor,
            Command::Keymap {
                command: KeymapCommand::Doctor { json },
            },
        ) => run_keymap_doctor(*json),
        (
            BuiltInHandlerId::KeymapExplain,
            Command::Keymap {
                command: KeymapCommand::Explain { key, mode, json },
            },
        ) => run_keymap_explain(key, mode.as_deref(), *json),
        (
            BuiltInHandlerId::TerminalDoctor,
            Command::Terminal {
                command:
                    TerminalCommand::Doctor {
                        json,
                        trace,
                        trace_limit,
                        trace_family,
                        trace_pane,
                    },
            },
        ) => run_terminal_doctor(*json, *trace, *trace_limit, *trace_family, *trace_pane),
        (
            BuiltInHandlerId::TerminalInstallTerminfo,
            Command::Terminal {
                command: TerminalCommand::InstallTerminfo { yes, check },
            },
        ) => run_terminal_install_terminfo(*yes, *check),
        (
            BuiltInHandlerId::RecordingStart,
            Command::Recording {
                command:
                    RecordingCommand::Start {
                        session_id,
                        no_capture_input,
                        name,
                        profile,
                        event_kind,
                    },
            },
        ) => {
            run_recording_start(
                session_id.as_deref(),
                !*no_capture_input,
                name.as_deref(),
                *profile,
                event_kind,
                connection_context,
            )
            .await
        }
        (
            BuiltInHandlerId::RecordingStop,
            Command::Recording {
                command: RecordingCommand::Stop { recording_id },
            },
        ) => run_recording_stop(recording_id.as_deref(), connection_context).await,
        (
            BuiltInHandlerId::RecordingStatus,
            Command::Recording {
                command: RecordingCommand::Status { json },
            },
        ) => run_recording_status(*json, connection_context).await,
        (
            BuiltInHandlerId::RecordingPath,
            Command::Recording {
                command: RecordingCommand::Path { json },
            },
        ) => run_recording_path(*json),
        (
            BuiltInHandlerId::RecordingList,
            Command::Recording {
                command:
                    RecordingCommand::List {
                        json,
                        limit,
                        all,
                        sort,
                        order,
                        status,
                        query,
                    },
            },
        ) => {
            run_recording_list(
                *json,
                recording::RecordingListOptions {
                    limit: *limit,
                    all: *all,
                    sort: *sort,
                    order: *order,
                    status: *status,
                    query: query.as_deref(),
                },
                connection_context,
            )
            .await
        }
        (
            BuiltInHandlerId::RecordingDelete,
            Command::Recording {
                command: RecordingCommand::Delete { recording_id },
            },
        ) => run_recording_delete(recording_id, connection_context).await,
        (
            BuiltInHandlerId::RecordingDeleteAll,
            Command::Recording {
                command: RecordingCommand::DeleteAll { yes },
            },
        ) => run_recording_delete_all(*yes, connection_context).await,
        (
            BuiltInHandlerId::RecordingCut,
            Command::Recording {
                command:
                    RecordingCommand::Cut {
                        last_seconds,
                        export_fps,
                        name,
                    },
            },
        ) => {
            run_recording_cut(
                *last_seconds,
                export_fps.as_ref().map(|fps| fps.get()),
                name.as_deref(),
                connection_context,
            )
            .await
        }
        (
            BuiltInHandlerId::RecordingInspect,
            Command::Recording {
                command:
                    RecordingCommand::Inspect {
                        recording_id,
                        limit,
                        kind,
                        json,
                    },
            },
        ) => run_recording_inspect(recording_id, *limit, kind.as_deref(), *json),
        (
            BuiltInHandlerId::RecordingAnalyze,
            Command::Recording {
                command:
                    RecordingCommand::Analyze {
                        recording_id,
                        perf,
                        json,
                    },
            },
        ) => run_recording_analyze(recording_id, *perf, *json),
        (
            BuiltInHandlerId::RecordingReplay,
            Command::Recording {
                command:
                    RecordingCommand::Replay {
                        recording_id,
                        mode,
                        speed,
                        target_bmux,
                        compare_recording,
                        ignore,
                        strict_timing,
                        max_verify_duration,
                        verify_start_timeout,
                    },
            },
        ) => {
            run_recording_replay(
                recording_id,
                *mode,
                *speed,
                target_bmux.as_deref(),
                compare_recording.as_deref(),
                ignore.as_deref(),
                *strict_timing,
                *max_verify_duration,
                *verify_start_timeout,
            )
            .await
        }
        (
            BuiltInHandlerId::RecordingVerifySmoke,
            Command::Recording {
                command:
                    RecordingCommand::VerifySmoke {
                        recording_id,
                        target_bmux,
                        compare_recording,
                        ignore,
                        strict_timing,
                        max_verify_duration,
                        verify_start_timeout,
                    },
            },
        ) => {
            run_recording_verify_smoke(
                recording_id,
                target_bmux.as_deref(),
                compare_recording.as_deref(),
                ignore.as_deref(),
                *strict_timing,
                *max_verify_duration,
                *verify_start_timeout,
            )
            .await
        }
        (
            BuiltInHandlerId::RecordingExport,
            Command::Recording {
                command:
                    RecordingCommand::Export {
                        recording_id,
                        format,
                        output,
                        view_client,
                        speed,
                        fps,
                        max_duration,
                        max_frames,
                        renderer,
                        cell_size,
                        cell_width,
                        cell_height,
                        font_family,
                        font_size,
                        line_height,
                        font_path,
                        palette_source,
                        palette_foreground,
                        palette_background,
                        palette_color,
                        cursor,
                        cursor_shape,
                        cursor_blink,
                        cursor_blink_period_ms,
                        cursor_color,
                        cursor_profile,
                        cursor_solid_after_activity_ms,
                        cursor_solid_after_input_ms,
                        cursor_solid_after_output_ms,
                        cursor_solid_after_cursor_ms,
                        cursor_paint_mode,
                        cursor_text_mode,
                        cursor_bar_width_pct,
                        cursor_underline_height_pct,
                        export_metadata,
                        no_progress,
                    },
            },
        ) => {
            run_recording_export(
                recording_id,
                *format,
                output,
                view_client.as_deref(),
                *speed,
                fps.as_ref().map(|fps| fps.get()),
                *max_duration,
                *max_frames,
                *renderer,
                *cell_size,
                *cell_width,
                *cell_height,
                font_family.as_deref(),
                *font_size,
                *line_height,
                font_path,
                *palette_source,
                palette_foreground.as_deref(),
                palette_background.as_deref(),
                palette_color,
                *cursor,
                *cursor_shape,
                *cursor_blink,
                *cursor_blink_period_ms,
                cursor_color.as_deref(),
                *cursor_profile,
                *cursor_solid_after_activity_ms,
                *cursor_solid_after_input_ms,
                *cursor_solid_after_output_ms,
                *cursor_solid_after_cursor_ms,
                *cursor_paint_mode,
                *cursor_text_mode,
                *cursor_bar_width_pct,
                *cursor_underline_height_pct,
                export_metadata.as_deref(),
                !*no_progress,
            )
            .await
        }
        (
            BuiltInHandlerId::RecordingPrune,
            Command::Recording {
                command: RecordingCommand::Prune { older_than, json },
            },
        ) => recording::run_recording_prune(*older_than, *json, connection_context).await,
        (
            BuiltInHandlerId::PlaybookRun,
            Command::Playbook {
                command:
                    PlaybookCommand::Run {
                        source,
                        json,
                        interactive,
                        target_server,
                        record,
                        export_gif,
                        viewport,
                        timeout,
                        shell,
                        vars,
                        verbose,
                    },
            },
        ) => {
            run_playbook_run(
                source,
                *json,
                *interactive,
                *target_server,
                *record,
                export_gif.as_deref(),
                viewport.as_deref(),
                *timeout,
                shell.as_deref(),
                vars,
                *verbose,
            )
            .await
        }
        (
            BuiltInHandlerId::PlaybookValidate,
            Command::Playbook {
                command: PlaybookCommand::Validate { source, json },
            },
        ) => run_playbook_validate(source, *json),
        (
            BuiltInHandlerId::PlaybookInteractive,
            Command::Playbook {
                command:
                    PlaybookCommand::Interactive {
                        socket,
                        record,
                        viewport,
                        shell,
                        timeout,
                    },
            },
        ) => {
            run_playbook_interactive(
                socket.as_deref(),
                *record,
                viewport,
                shell.as_deref(),
                *timeout,
            )
            .await
        }
        (
            BuiltInHandlerId::PlaybookFromRecording,
            Command::Playbook {
                command:
                    PlaybookCommand::FromRecording {
                        recording_id,
                        output,
                    },
            },
        ) => run_playbook_from_recording(recording_id, output.as_deref()),
        (
            BuiltInHandlerId::PlaybookDryRun,
            Command::Playbook {
                command: PlaybookCommand::DryRun { source, json },
            },
        ) => run_playbook_dry_run(source, *json),
        (
            BuiltInHandlerId::PlaybookDiff,
            Command::Playbook {
                command:
                    PlaybookCommand::Diff {
                        left,
                        right,
                        json,
                        timing_threshold,
                    },
            },
        ) => run_playbook_diff(left, right, *json, *timing_threshold),
        (
            BuiltInHandlerId::PlaybookCleanup,
            Command::Playbook {
                command: PlaybookCommand::Cleanup { dry_run, json },
            },
        ) => run_playbook_cleanup(*dry_run, *json),
        (
            BuiltInHandlerId::SandboxDev,
            Command::Sandbox {
                command:
                    SandboxCommand::Dev {
                        bmux_bin,
                        env_mode,
                        json,
                        print_env,
                        timeout,
                        name,
                        command,
                    },
            },
        ) => {
            let dev_bmux_bin = default_dev_bmux_bin();
            let options = RunSandboxOptions {
                bmux_bin: bmux_bin.as_deref().or(dev_bmux_bin.as_deref()),
                env_mode: *env_mode,
                keep: true,
                json: *json,
                print_env: *print_env,
                timeout_secs: *timeout,
                name: name.as_deref(),
            };
            run_sandbox_run(options, command).await
        }
        (
            BuiltInHandlerId::SandboxRun,
            Command::Sandbox {
                command:
                    SandboxCommand::Run {
                        bmux_bin,
                        env_mode,
                        keep,
                        json,
                        print_env,
                        timeout,
                        name,
                        command,
                    },
            },
        ) => {
            let options = RunSandboxOptions {
                bmux_bin: bmux_bin.as_deref(),
                env_mode: *env_mode,
                keep: *keep,
                json: *json,
                print_env: *print_env,
                timeout_secs: *timeout,
                name: name.as_deref(),
            };
            run_sandbox_run(options, command).await
        }
        (
            BuiltInHandlerId::SandboxList,
            Command::Sandbox {
                command:
                    SandboxCommand::List {
                        status,
                        source,
                        limit,
                        json,
                    },
            },
        ) => {
            let status_filter = match status {
                SandboxStatusArg::Running => Some("running"),
                SandboxStatusArg::Stopped => Some("stopped"),
                SandboxStatusArg::Failed => Some("failed"),
                SandboxStatusArg::All => None,
            };
            let source_filter = match source {
                SandboxSourceArg::SandboxCli => Some("sandbox-cli"),
                SandboxSourceArg::Playbook => Some("playbook"),
                SandboxSourceArg::RecordingVerify => Some("recording-verify"),
                SandboxSourceArg::All => None,
            };
            run_sandbox_list(status_filter, source_filter, *limit, *json)
        }
        (
            BuiltInHandlerId::SandboxStatus,
            Command::Sandbox {
                command: SandboxCommand::Status { json },
            },
        ) => run_sandbox_status(*json),
        (
            BuiltInHandlerId::SandboxInspect,
            Command::Sandbox {
                command:
                    SandboxCommand::Inspect {
                        sandbox,
                        latest,
                        latest_failed,
                        source,
                        tail,
                        json,
                    },
            },
        ) => {
            let source_filter = sandbox_source_filter(*source);
            run_sandbox_inspect(
                sandbox.as_deref(),
                *latest,
                *latest_failed,
                source_filter,
                *tail,
                *json,
            )
        }
        (
            BuiltInHandlerId::SandboxTail,
            Command::Sandbox {
                command:
                    SandboxCommand::Tail {
                        sandbox,
                        latest,
                        latest_failed,
                        source,
                        tail,
                        json,
                    },
            },
        ) => {
            let source_filter = sandbox_source_filter(*source);
            run_sandbox_tail(
                sandbox.as_deref(),
                *latest,
                *latest_failed,
                source_filter,
                *tail,
                *json,
            )
        }
        (
            BuiltInHandlerId::SandboxOpen,
            Command::Sandbox {
                command:
                    SandboxCommand::Open {
                        sandbox,
                        latest,
                        latest_failed,
                        source,
                        json,
                    },
            },
        ) => {
            let source_filter = sandbox_source_filter(*source);
            run_sandbox_open(
                sandbox.as_deref(),
                *latest,
                *latest_failed,
                source_filter,
                *json,
            )
        }
        (
            BuiltInHandlerId::SandboxRerun,
            Command::Sandbox {
                command:
                    SandboxCommand::Rerun {
                        sandbox,
                        latest,
                        latest_failed,
                        source,
                        bmux_bin,
                        env_mode,
                        keep,
                        json,
                        print_env,
                        timeout,
                        name,
                    },
            },
        ) => {
            let source_filter = sandbox_source_filter(*source);
            run_sandbox_rerun(RerunSandboxOptions {
                inspect: InspectTargetOptions {
                    target: sandbox.as_deref(),
                    latest: *latest,
                    latest_failed: *latest_failed,
                    source_filter,
                },
                run: RunSandboxOptions {
                    bmux_bin: None,
                    env_mode: SandboxEnvModeArg::Inherit,
                    keep: *keep,
                    json: *json,
                    print_env: *print_env,
                    timeout_secs: *timeout,
                    name: name.as_deref(),
                },
                bmux_bin_override: bmux_bin.as_deref(),
                env_mode_override: *env_mode,
            })
            .await
        }
        (
            BuiltInHandlerId::SandboxTriage,
            Command::Sandbox {
                command:
                    SandboxCommand::Triage {
                        sandbox,
                        latest,
                        latest_failed,
                        source,
                        tail,
                        rerun,
                        bmux_bin,
                        env_mode,
                        keep,
                        print_env,
                        timeout,
                        name,
                        bundle,
                        bundle_output,
                        bundle_strict_verify,
                        json,
                    },
            },
        ) => {
            let source_filter = sandbox_source_filter(*source);
            run_sandbox_triage(TriageSandboxOptions {
                inspect: InspectTargetOptions {
                    target: sandbox.as_deref(),
                    latest: *latest,
                    latest_failed: *latest_failed,
                    source_filter,
                },
                tail: *tail,
                rerun: *rerun,
                run: RunSandboxOptions {
                    bmux_bin: None,
                    env_mode: SandboxEnvModeArg::Inherit,
                    keep: *keep,
                    json: false,
                    print_env: *print_env,
                    timeout_secs: *timeout,
                    name: name.as_deref(),
                },
                bmux_bin_override: bmux_bin.as_deref(),
                env_mode_override: *env_mode,
                bundle: bundle.then_some(TriageBundleOptions {
                    output: bundle_output.as_deref(),
                    strict_verify: *bundle_strict_verify,
                }),
                json: *json,
            })
            .await
        }
        (
            BuiltInHandlerId::SandboxDoctor,
            Command::Sandbox {
                command:
                    SandboxCommand::Doctor {
                        id,
                        fix,
                        dry_run,
                        json,
                    },
            },
        ) => run_sandbox_doctor(id.as_deref(), *fix, *dry_run, *json),
        (
            BuiltInHandlerId::SandboxBundle,
            Command::Sandbox {
                command:
                    SandboxCommand::Bundle {
                        sandbox,
                        output,
                        include_env,
                        include_index_state,
                        include_doctor,
                        verify,
                        json,
                    },
            },
        ) => run_sandbox_bundle(&BundleSandboxOptions {
            target: sandbox,
            output: output.as_deref(),
            include: BundleIncludeOptions {
                env: *include_env,
                index_state: *include_index_state,
                doctor: *include_doctor,
            },
            verify: *verify,
            json: *json,
        }),
        (
            BuiltInHandlerId::SandboxCleanup,
            Command::Sandbox {
                command:
                    SandboxCommand::Cleanup {
                        dry_run,
                        failed_only,
                        all_status,
                        older_than,
                        source,
                        json,
                    },
            },
        ) => {
            let config = BmuxConfig::load().unwrap_or_default();
            let defaults = config.sandbox.cleanup;

            let resolved_failed_only =
                bool_override(*failed_only, *all_status).unwrap_or(defaults.failed_only);
            let resolved_older_than = older_than.unwrap_or(defaults.older_than_secs);

            let source_arg = source.as_ref().copied().unwrap_or(match defaults.source {
                SandboxCleanupSource::SandboxCli => SandboxSourceArg::SandboxCli,
                SandboxCleanupSource::Playbook => SandboxSourceArg::Playbook,
                SandboxCleanupSource::RecordingVerify => SandboxSourceArg::RecordingVerify,
                SandboxCleanupSource::All => SandboxSourceArg::All,
            });
            let source_filter = sandbox_source_filter(source_arg);

            run_sandbox_cleanup(
                *dry_run,
                resolved_failed_only,
                Some(resolved_older_than),
                source_filter,
                *json,
            )
        }
        (
            BuiltInHandlerId::SandboxVerifyBundle,
            Command::Sandbox {
                command:
                    SandboxCommand::VerifyBundle {
                        bundle_dir,
                        strict,
                        json,
                    },
            },
        ) => run_sandbox_verify_bundle(bundle_dir, *strict, *json),
        (
            BuiltInHandlerId::SandboxRebuildIndex,
            Command::Sandbox {
                command: SandboxCommand::RebuildIndex { json },
            },
        ) => run_sandbox_rebuild_index(*json),
        (
            BuiltInHandlerId::SandboxClean,
            Command::Sandbox {
                command:
                    SandboxCommand::Clean {
                        dry_run,
                        all_status,
                        older_than,
                        source,
                        json,
                    },
            },
        ) => {
            let source_filter =
                sandbox_source_filter(source.as_ref().copied().unwrap_or(SandboxSourceArg::All));

            let resolved_failed_only = !all_status;
            let resolved_older_than = older_than.unwrap_or(600);
            run_sandbox_cleanup(
                *dry_run,
                resolved_failed_only,
                Some(resolved_older_than),
                source_filter,
                *json,
            )
        }
        (
            BuiltInHandlerId::SlotList,
            Command::Slot {
                command: SlotCommand::List { format },
            }
            | Command::Env {
                command: SlotCommand::List { format },
            },
        ) => super::slot_cli::run_slot_list(*format),
        (
            BuiltInHandlerId::SlotShow,
            Command::Slot {
                command: SlotCommand::Show { name, format },
            }
            | Command::Env {
                command: SlotCommand::Show { name, format },
            },
        ) => super::slot_cli::run_slot_show(name.as_deref(), *format),
        (
            BuiltInHandlerId::SlotPaths,
            Command::Slot {
                command: SlotCommand::Paths { name },
            }
            | Command::Env {
                command: SlotCommand::Paths { name },
            },
        ) => super::slot_cli::run_slot_paths(name.as_deref()),
        (
            BuiltInHandlerId::SlotDoctor,
            Command::Slot {
                command: SlotCommand::Doctor,
            }
            | Command::Env {
                command: SlotCommand::Doctor,
            },
        ) => super::slot_cli::run_slot_doctor(),
        (
            BuiltInHandlerId::SlotInstall,
            Command::Slot {
                command:
                    SlotCommand::Install {
                        name,
                        binary,
                        no_inherit_base,
                        mode,
                        bin_dir,
                        format,
                        dry_run,
                        overwrite,
                        yes,
                    },
            }
            | Command::Env {
                command:
                    SlotCommand::Install {
                        name,
                        binary,
                        no_inherit_base,
                        mode,
                        bin_dir,
                        format,
                        dry_run,
                        overwrite,
                        yes,
                    },
            },
        ) => super::slot_cli::run_slot_install(super::slot_cli::SlotInstallOptions {
            name,
            binary,
            inherit_base: !*no_inherit_base,
            mode: *mode,
            bin_dir: bin_dir.as_deref(),
            format: *format,
            dry_run: *dry_run,
            overwrite: *overwrite,
            yes: *yes,
        }),
        (
            BuiltInHandlerId::SlotUninstall,
            Command::Slot {
                command:
                    SlotCommand::Uninstall {
                        name,
                        purge,
                        bin_dir,
                    },
            }
            | Command::Env {
                command:
                    SlotCommand::Uninstall {
                        name,
                        purge,
                        bin_dir,
                    },
            },
        ) => super::slot_cli::run_slot_uninstall(name, *purge, bin_dir.as_deref()),
        (
            BuiltInHandlerId::SlotShell,
            Command::Slot {
                command: SlotCommand::Shell { shell },
            }
            | Command::Env {
                command: SlotCommand::Shell { shell },
            },
        ) => super::slot_cli::run_slot_shell(*shell),
        (
            BuiltInHandlerId::SlotExec,
            Command::Slot {
                command: SlotCommand::Exec { slot, argv },
            }
            | Command::Env {
                command: SlotCommand::Exec { slot, argv },
            },
        ) => super::slot_cli::run_slot_exec(slot, argv),
        (
            BuiltInHandlerId::SlotPrint,
            Command::Slot {
                command: SlotCommand::Print { format },
            }
            | Command::Env {
                command: SlotCommand::Print { format },
            },
        ) => super::slot_cli::run_slot_print(*format),
        _ => unreachable!("built-in command handler and command variant should stay in sync"),
    }
}

fn default_dev_bmux_bin() -> Option<String> {
    let candidate = std::path::Path::new("target").join("debug").join("bmux");
    candidate
        .exists()
        .then(|| candidate.to_string_lossy().to_string())
}

const fn bool_override(positive: bool, negative: bool) -> Option<bool> {
    if positive {
        Some(true)
    } else if negative {
        Some(false)
    } else {
        None
    }
}

const fn sandbox_source_filter(source: SandboxSourceArg) -> Option<&'static str> {
    match source {
        SandboxSourceArg::SandboxCli => Some("sandbox-cli"),
        SandboxSourceArg::Playbook => Some("playbook"),
        SandboxSourceArg::RecordingVerify => Some("recording-verify"),
        SandboxSourceArg::All => None,
    }
}

fn all_recording_event_kinds() -> Vec<RecordingEventKind> {
    vec![
        RecordingEventKind::PaneInputRaw,
        RecordingEventKind::PaneOutputRaw,
        RecordingEventKind::ProtocolReplyRaw,
        RecordingEventKind::PaneImage,
        RecordingEventKind::ServerEvent,
        RecordingEventKind::RequestStart,
        RecordingEventKind::RequestDone,
        RecordingEventKind::RequestError,
        RecordingEventKind::Custom,
    ]
}

const fn recording_event_kind_arg_to_ipc(kind: RecordingEventKindArg) -> RecordingEventKind {
    match kind {
        RecordingEventKindArg::PaneInputRaw => RecordingEventKind::PaneInputRaw,
        RecordingEventKindArg::PaneOutputRaw => RecordingEventKind::PaneOutputRaw,
        RecordingEventKindArg::ProtocolReplyRaw => RecordingEventKind::ProtocolReplyRaw,
        RecordingEventKindArg::PaneImage => RecordingEventKind::PaneImage,
        RecordingEventKindArg::ServerEvent => RecordingEventKind::ServerEvent,
        RecordingEventKindArg::RequestStart => RecordingEventKind::RequestStart,
        RecordingEventKindArg::RequestDone => RecordingEventKind::RequestDone,
        RecordingEventKindArg::RequestError => RecordingEventKind::RequestError,
        RecordingEventKindArg::Custom => RecordingEventKind::Custom,
    }
}

#[cfg(test)]
mod tests {
    #[allow(clippy::wildcard_imports)]
    use super::*;

    #[test]
    fn built_in_handler_maps_config_profiles_explain() {
        let command = Command::Config {
            command: ConfigCommand::Profiles {
                command: ConfigProfilesCommand::Explain {
                    profile: Some("vim".to_string()),
                    json: false,
                },
            },
        };
        assert_eq!(
            built_in_handler_for_command(&command),
            BuiltInHandlerId::ConfigProfilesExplain
        );
    }

    #[test]
    fn built_in_handler_maps_config_profiles_switch_with_dry_run() {
        let command = Command::Config {
            command: ConfigCommand::Profiles {
                command: ConfigProfilesCommand::Switch {
                    profile: "tmux_compat".to_string(),
                    dry_run: true,
                    json: true,
                },
            },
        };
        assert_eq!(
            built_in_handler_for_command(&command),
            BuiltInHandlerId::ConfigProfilesSwitch
        );
    }

    #[test]
    fn built_in_handler_maps_keymap_explain() {
        let command = Command::Keymap {
            command: KeymapCommand::Explain {
                key: "ctrl+b n".to_string(),
                mode: Some("normal".to_string()),
                json: true,
            },
        };
        assert_eq!(
            built_in_handler_for_command(&command),
            BuiltInHandlerId::KeymapExplain
        );
    }
}
