use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
use serde_json::{Value, json};

use kura_cli::commands;
use kura_cli::commands::public_tasks::{
    public_plan_activity_payload_contract, public_record_activity_payload_contract,
    public_record_benchmark_payload_contract, public_record_measurement_payload_contract,
    public_record_nutrition_payload_contract, public_record_recovery_payload_contract,
    public_report_health_payload_contract, public_update_plan_payload_contract,
    public_update_profile_payload_contract,
};
use kura_cli::util::{
    CliOutputMode, CliRuntimeOptions, exit_error, print_json_stderr, print_json_stdout,
    resolve_token, set_cli_runtime_options,
};

#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
enum OutputFormatArg {
    Json,
    JsonCompact,
}

impl From<OutputFormatArg> for CliOutputMode {
    fn from(value: OutputFormatArg) -> Self {
        match value {
            OutputFormatArg::Json => CliOutputMode::Json,
            OutputFormatArg::JsonCompact => CliOutputMode::JsonCompact,
        }
    }
}

#[derive(Parser)]
#[command(name = "kura", version, about = "Kura CLI — agent-first task surface")]
struct Cli {
    /// API base URL
    #[arg(
        long,
        global = true,
        env = "KURA_API_URL",
        default_value = "http://localhost:3000"
    )]
    api_url: String,

    /// Skip credential check (for use behind an auth-injecting proxy)
    #[arg(long, global = true, env = "KURA_NO_AUTH")]
    no_auth: bool,

    /// JSON output format
    #[arg(long, global = true, value_enum, default_value_t = OutputFormatArg::Json, env = "KURA_OUTPUT")]
    output: OutputFormatArg,

    /// Suppress non-JSON stderr lines (notices/progress)
    #[arg(long, global = true, env = "KURA_QUIET_STDERR")]
    quiet_stderr: bool,

    /// Do not execute mutating operations (POST/PUT/PATCH/DELETE)
    #[arg(long, global = true, env = "KURA_DRY_RUN")]
    dry_run: bool,

    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Record one executed activity session
    #[command(name = "record_activity")]
    RecordActivity(commands::public_tasks::RecordActivityArgs),

    /// Record one recovery check-in
    #[command(name = "record_recovery")]
    RecordRecovery(commands::public_tasks::RecordRecoveryArgs),

    /// Report one injury or illness episode
    #[command(name = "report_health")]
    ReportHealth(commands::public_tasks::ReportHealthArgs),

    /// Record one meal or nutrition target
    #[command(name = "record_nutrition")]
    RecordNutrition(commands::public_tasks::RecordNutritionArgs),

    /// Record one body-measurement snapshot
    #[command(name = "record_measurement")]
    RecordMeasurement(commands::public_tasks::RecordMeasurementArgs),

    /// Record one formal benchmark result
    #[command(name = "record_benchmark")]
    RecordBenchmark(commands::public_tasks::RecordBenchmarkArgs),

    /// Plan one future or not-yet-executed activity session
    #[command(name = "plan_activity")]
    PlanActivity(commands::public_tasks::PlanActivityArgs),

    /// Update durable profile context and optional profile-adjacent baselines
    #[command(name = "update_profile")]
    UpdateProfile(commands::public_tasks::UpdateProfileArgs),

    /// Update one future plan or schedule change
    #[command(name = "update_plan")]
    UpdatePlan(commands::public_tasks::UpdatePlanArgs),

    /// Run one declarative canonical read
    #[command(name = "read_query")]
    ReadQuery(commands::read::ReadQueryArgs),

    /// Run one bounded deep analysis
    #[command(name = "analyze")]
    Analyze(commands::analysis::AnalyzeArgs),

    /// Specialist developer surfaces and raw tooling
    #[command(hide = true)]
    Dev {
        #[command(subcommand)]
        command: commands::dev::DevCommands,
    },

    /// Specialist admin, account, and access surfaces
    #[command(hide = true)]
    Admin {
        #[command(subcommand)]
        command: commands::public_admin::PublicAdminCommands,
    },

    /// Check API health
    #[command(hide = true)]
    Health,

    /// Access request operations
    #[command(hide = true)]
    Access {
        #[command(subcommand)]
        command: commands::access::AccessCommands,
    },

    /// Direct API access (like gh api — works with any endpoint)
    #[command(hide = true)]
    Api(commands::api::ApiArgs),

    /// Execute one request from a JSON envelope file (defaults to stdin)
    #[command(hide = true)]
    Exec(commands::exec::ExecArgs),

    /// Emit machine-readable schema for CLI commands/args
    #[command(hide = true)]
    Schema {
        /// Optional command path, e.g. `dev api` or `record_activity`
        #[arg(value_name = "COMMAND", num_args = 0..)]
        path: Vec<String>,
    },

    /// Event operations (create, list, batch)
    #[command(hide = true)]
    Event {
        #[command(subcommand)]
        command: commands::event::EventCommands,
    },

    /// Projection operations (get, list)
    #[command(hide = true)]
    Projection {
        #[command(subcommand)]
        command: commands::projection::ProjectionCommands,
    },

    /// Agent diagnostics, context, evidence, preferences, and visualization surfaces
    #[command(hide = true)]
    Agent {
        #[command(subcommand)]
        command: commands::agent::AgentCommands,
    },

    /// Observation workflows (draft visibility + promotion)
    #[command(hide = true)]
    Observation {
        #[command(subcommand)]
        command: commands::observation::ObservationCommands,
    },

    /// MCP server operations (Model Context Protocol over stdio)
    #[command(hide = true)]
    Mcp {
        #[command(subcommand)]
        command: commands::mcp::McpCommands,
    },

    /// External import job operations
    #[command(hide = true)]
    Import {
        #[command(subcommand)]
        command: commands::imports::ImportCommands,
    },

    /// Provider connection operations
    #[command(hide = true)]
    Provider {
        #[command(subcommand)]
        command: commands::provider::ProviderCommands,
    },

    /// Offline replay evaluation wrappers (worker-backed)
    #[command(hide = true)]
    Eval {
        #[command(subcommand)]
        command: commands::eval::EvalCommands,
    },

    /// Get all projections in one call (agent bootstrap snapshot)
    #[command(hide = true)]
    Snapshot,

    /// Get system configuration (dimensions, conventions, event types)
    #[command(hide = true)]
    Config,

    /// Diagnose setup: API, auth, worker, system config
    #[command(hide = true)]
    Doctor,

    /// Account operations
    #[command(hide = true)]
    Account {
        #[command(subcommand)]
        command: commands::account::AccountCommands,
    },

    /// Authenticate with the Kura API via OAuth
    #[command(hide = true)]
    Login {
        /// Use OAuth Device Authorization flow (code entry in browser UI)
        #[arg(long)]
        device: bool,
    },

    /// Remove stored credentials
    #[command(hide = true)]
    Logout,
}

#[tokio::main]
async fn main() {
    let _ = dotenvy::dotenv();
    let cli = Cli::parse();

    set_cli_runtime_options(CliRuntimeOptions {
        output_mode: cli.output.into(),
        quiet_stderr: cli.quiet_stderr,
        dry_run: cli.dry_run,
    });

    let code = match cli.command {
        Commands::RecordActivity(args) => {
            commands::public_tasks::run_record_activity(&cli.api_url, cli.no_auth, args).await
        }
        Commands::RecordRecovery(args) => {
            commands::public_tasks::run_record_recovery(&cli.api_url, cli.no_auth, args).await
        }
        Commands::ReportHealth(args) => {
            commands::public_tasks::run_report_health(&cli.api_url, cli.no_auth, args).await
        }
        Commands::RecordNutrition(args) => {
            commands::public_tasks::run_record_nutrition(&cli.api_url, cli.no_auth, args).await
        }
        Commands::RecordMeasurement(args) => {
            commands::public_tasks::run_record_measurement(&cli.api_url, cli.no_auth, args).await
        }
        Commands::RecordBenchmark(args) => {
            commands::public_tasks::run_record_benchmark(&cli.api_url, cli.no_auth, args).await
        }
        Commands::PlanActivity(args) => {
            commands::public_tasks::run_plan_activity(&cli.api_url, cli.no_auth, args).await
        }
        Commands::UpdateProfile(args) => {
            commands::public_tasks::run_update_profile(&cli.api_url, cli.no_auth, args).await
        }
        Commands::UpdatePlan(args) => {
            commands::public_tasks::run_update_plan(&cli.api_url, cli.no_auth, args).await
        }
        Commands::ReadQuery(args) => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::read::run_query(&cli.api_url, token.as_deref(), args).await
        }
        Commands::Analyze(args) => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::analysis::analyze(&cli.api_url, token.as_deref(), args).await
        }
        Commands::Projection { command } => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::projection::run(&cli.api_url, token.as_deref(), command).await
        }

        Commands::Dev { command } => run_dev_command(&cli.api_url, cli.no_auth, command).await,

        Commands::Admin { command } => {
            run_public_admin_command(&cli.api_url, cli.no_auth, command).await
        }

        Commands::Health => commands::health::run(&cli.api_url).await,

        Commands::Access { command } => commands::access::run(&cli.api_url, command).await,

        Commands::Api(mut args) => {
            if cli.no_auth {
                args.no_auth = true;
            }
            commands::api::run(&cli.api_url, args).await
        }

        Commands::Exec(args) => commands::exec::run(&cli.api_url, cli.no_auth, args).await,

        Commands::Schema { path } => emit_cli_schema(&path),

        Commands::Event { command } => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::event::run(&cli.api_url, token.as_deref(), command).await
        }

        Commands::Agent { command } => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::agent::run(&cli.api_url, token.as_deref(), command).await
        }

        Commands::Observation { command } => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::observation::run(&cli.api_url, token.as_deref(), command).await
        }

        Commands::Mcp { command } => commands::mcp::run(&cli.api_url, cli.no_auth, command).await,

        Commands::Import { command } => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::imports::run(&cli.api_url, token.as_deref(), command).await
        }

        Commands::Provider { command } => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::provider::run(&cli.api_url, token.as_deref(), command).await
        }

        Commands::Eval { command } => commands::eval::run(command).await,

        Commands::Snapshot => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::system::snapshot(&cli.api_url, token.as_deref()).await
        }

        Commands::Config => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::system::config(&cli.api_url, token.as_deref()).await
        }

        Commands::Doctor => commands::system::doctor(&cli.api_url).await,

        Commands::Account { command } => {
            let token = resolve_or_exit(&cli.api_url, cli.no_auth).await;
            commands::account::run(&cli.api_url, token.as_deref(), command).await
        }

        Commands::Login { device } => {
            if let Err(e) = commands::auth::login(&cli.api_url, device).await {
                exit_error(&e.to_string(), None);
            }
            0
        }

        Commands::Logout => {
            if let Err(e) = commands::auth::logout() {
                exit_error(&e.to_string(), None);
            }
            0
        }
    };

    std::process::exit(code);
}

fn emit_cli_schema(path: &[String]) -> i32 {
    let root = Cli::command();
    let command = match resolve_schema_path(root, path) {
        Ok(command) => command,
        Err((message, available_subcommands)) => {
            let err = json!({
                "error": "usage_error",
                "message": message,
                "available_subcommands": available_subcommands,
            });
            print_json_stderr(&err);
            return 4;
        }
    };

    let mut payload = command_schema(&command);
    if let Some(contract) = payload_contract_for_path(path) {
        payload["payload_contract"] = contract;
    }
    payload["requested_path"] = json!(path);
    print_json_stdout(&payload);
    0
}

async fn run_dev_command(api_url: &str, no_auth: bool, command: commands::dev::DevCommands) -> i32 {
    match command {
        commands::dev::DevCommands::Health => commands::health::run(api_url).await,
        commands::dev::DevCommands::Api(mut args) => {
            if no_auth {
                args.no_auth = true;
            }
            commands::api::run(api_url, args).await
        }
        commands::dev::DevCommands::Exec(args) => commands::exec::run(api_url, no_auth, args).await,
        commands::dev::DevCommands::Schema { path } => emit_cli_schema(&path),
        commands::dev::DevCommands::Event { command } => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::event::run(api_url, token.as_deref(), command).await
        }
        commands::dev::DevCommands::Projection { command } => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::projection::run(api_url, token.as_deref(), command).await
        }
        commands::dev::DevCommands::Agent { command } => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::agent::run(api_url, token.as_deref(), command).await
        }
        commands::dev::DevCommands::Observation { command } => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::observation::run(api_url, token.as_deref(), command).await
        }
        commands::dev::DevCommands::Mcp { command } => {
            commands::mcp::run(api_url, no_auth, command).await
        }
        commands::dev::DevCommands::Import { command } => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::imports::run(api_url, token.as_deref(), command).await
        }
        commands::dev::DevCommands::Provider { command } => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::provider::run(api_url, token.as_deref(), command).await
        }
        commands::dev::DevCommands::Eval { command } => commands::eval::run(command).await,
        commands::dev::DevCommands::Snapshot => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::system::snapshot(api_url, token.as_deref()).await
        }
        commands::dev::DevCommands::Config => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::system::config(api_url, token.as_deref()).await
        }
        commands::dev::DevCommands::Doctor => commands::system::doctor(api_url).await,
    }
}

async fn run_public_admin_command(
    api_url: &str,
    no_auth: bool,
    command: commands::public_admin::PublicAdminCommands,
) -> i32 {
    match command {
        commands::public_admin::PublicAdminCommands::Access { command } => {
            commands::access::run(api_url, command).await
        }
        commands::public_admin::PublicAdminCommands::Account { command } => {
            let token = resolve_or_exit(api_url, no_auth).await;
            commands::account::run(api_url, token.as_deref(), command).await
        }
        commands::public_admin::PublicAdminCommands::Login { device } => {
            if let Err(e) = commands::auth::login(api_url, device).await {
                exit_error(&e.to_string(), None);
            }
            0
        }
        commands::public_admin::PublicAdminCommands::Logout => {
            if let Err(e) = commands::auth::logout() {
                exit_error(&e.to_string(), None);
            }
            0
        }
        commands::public_admin::PublicAdminCommands::Ops { command } => {
            run_raw_admin_command(api_url, no_auth, command).await
        }
        commands::public_admin::PublicAdminCommands::CreateUser {
            email,
            password,
            display_name,
        } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::CreateUser {
                    email,
                    password,
                    display_name,
                },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::CreateKey {
            user_id,
            label,
            expires_in_days,
        } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::CreateKey {
                    user_id,
                    label,
                    expires_in_days,
                },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::DeleteUser { user_id, confirm } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::DeleteUser { user_id, confirm },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::ListRequests { status } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::ListRequests { status },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::ApproveRequest { id } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::ApproveRequest { id },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::RejectRequest { id } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::RejectRequest { id },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::CreateInvite {
            email,
            expires_in_days,
        } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::CreateInvite {
                    email,
                    expires_in_days,
                },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::ListInvites { status } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::ListInvites { status },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::SupportReidentify {
            user_id,
            reason,
            ticket_id,
            requested_mode,
            expires_at,
        } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::SupportReidentify {
                    user_id,
                    reason,
                    ticket_id,
                    requested_mode,
                    expires_at,
                },
            )
            .await
        }
        commands::public_admin::PublicAdminCommands::Telemetry { command } => {
            run_raw_admin_command(
                api_url,
                no_auth,
                commands::admin::AdminCommands::Telemetry { command },
            )
            .await
        }
    }
}

async fn run_raw_admin_command(
    api_url: &str,
    no_auth: bool,
    command: commands::admin::AdminCommands,
) -> i32 {
    commands::admin::ensure_admin_surface_enabled_or_exit();
    let token = if commands::admin::requires_api_auth(&command) {
        resolve_or_exit(api_url, no_auth).await
    } else {
        None
    };
    commands::admin::run(api_url, token.as_deref(), command).await
}

fn resolve_schema_path(
    mut command: clap::Command,
    path: &[String],
) -> Result<clap::Command, (String, Vec<String>)> {
    for segment in path {
        let next = command
            .get_subcommands()
            .find(|candidate| candidate.get_name() == segment)
            .cloned();

        match next {
            Some(candidate) => {
                command = candidate;
            }
            None => {
                let available_subcommands: Vec<String> = command
                    .get_subcommands()
                    .filter(|candidate| !candidate.is_hide_set())
                    .map(|candidate| candidate.get_name().to_string())
                    .collect();
                return Err((
                    format!("Unknown command path segment '{segment}' while resolving schema."),
                    available_subcommands,
                ));
            }
        }
    }

    Ok(command)
}

fn command_schema(command: &clap::Command) -> Value {
    let args: Vec<Value> = command
        .get_arguments()
        .filter(|arg| !arg.is_hide_set())
        .map(arg_schema)
        .collect();

    let subcommands: Vec<Value> = command
        .get_subcommands()
        .filter(|child| !child.is_hide_set())
        .map(|child| {
            json!({
                "name": child.get_name(),
                "about": child.get_about().map(|value| value.to_string())
            })
        })
        .collect();

    json!({
        "schema_version": "kura.cli.schema.v1",
        "name": command.get_name(),
        "about": command.get_about().map(|value| value.to_string()),
        "args": args,
        "subcommands": subcommands,
    })
}

fn payload_contract_for_path(path: &[String]) -> Option<Value> {
    match path {
        [command] if command == "record_activity" => {
            Some(public_record_activity_payload_contract())
        }
        [command] if command == "record_recovery" => {
            Some(public_record_recovery_payload_contract())
        }
        [command] if command == "report_health" => Some(public_report_health_payload_contract()),
        [command] if command == "record_nutrition" => {
            Some(public_record_nutrition_payload_contract())
        }
        [command] if command == "record_measurement" => {
            Some(public_record_measurement_payload_contract())
        }
        [command] if command == "record_benchmark" => {
            Some(public_record_benchmark_payload_contract())
        }
        [command] if command == "plan_activity" => Some(public_plan_activity_payload_contract()),
        [command] if command == "update_profile" => Some(public_update_profile_payload_contract()),
        [command] if command == "update_plan" => Some(public_update_plan_payload_contract()),
        [read_query] if read_query == "read_query" => {
            Some(commands::read::public_read_query_payload_contract())
        }
        [analyze] if analyze == "analyze" => {
            Some(commands::analysis::public_analyze_payload_contract())
        }
        _ => None,
    }
}

fn arg_schema(arg: &clap::Arg) -> Value {
    let value_names: Vec<String> = arg
        .get_value_names()
        .map(|names| names.iter().map(|name| name.to_string()).collect())
        .unwrap_or_default();

    let default_values: Vec<String> = arg
        .get_default_values()
        .iter()
        .map(|value| value.to_string_lossy().to_string())
        .collect();

    let mut payload = json!({
        "id": arg.get_id().as_str(),
        "long": arg.get_long(),
        "short": arg.get_short().map(|value| value.to_string()),
        "required": arg.is_required_set(),
        "action": format!("{:?}", arg.get_action()),
        "help": arg.get_help().map(|value| value.to_string()),
        "value_names": value_names,
        "default_values": default_values,
    });

    if let Some(num_args) = arg.get_num_args() {
        payload["num_args"] = json!(format!("{num_args:?}"));
    }

    payload
}

async fn resolve_or_exit(api_url: &str, no_auth: bool) -> Option<String> {
    if no_auth {
        return None;
    }
    match resolve_token(api_url).await {
        Ok(t) => Some(t),
        Err(e) => exit_error(&e.to_string(), Some("Run `kura login` or set KURA_API_KEY")),
    }
}

#[cfg(test)]
mod tests {
    use super::{Cli, command_schema, payload_contract_for_path, resolve_schema_path};
    use clap::CommandFactory;
    use serde_json::json;

    fn schema_for(path: &[&str]) -> serde_json::Value {
        let root = Cli::command();
        let path = path
            .iter()
            .map(|segment| segment.to_string())
            .collect::<Vec<_>>();
        let command = resolve_schema_path(root, &path).expect("schema path should resolve");
        let mut schema = command_schema(&command);
        if let Some(contract) = payload_contract_for_path(&path) {
            schema["payload_contract"] = contract;
        }
        schema
    }

    #[test]
    fn root_schema_lists_only_new_public_shell() {
        let schema = schema_for(&[]);
        assert_eq!(
            schema["subcommands"],
            json!([
                {"name": "record_activity", "about": "Record one executed activity session"},
                {"name": "record_recovery", "about": "Record one recovery check-in"},
                {"name": "report_health", "about": "Report one injury or illness episode"},
                {"name": "record_nutrition", "about": "Record one meal or nutrition target"},
                {"name": "record_measurement", "about": "Record one body-measurement snapshot"},
                {"name": "record_benchmark", "about": "Record one formal benchmark result"},
                {"name": "plan_activity", "about": "Plan one future or not-yet-executed activity session"},
                {"name": "update_profile", "about": "Update durable profile context and optional profile-adjacent baselines"},
                {"name": "update_plan", "about": "Update one future plan or schedule change"},
                {"name": "read_query", "about": "Run one declarative canonical read"},
                {"name": "analyze", "about": "Run one bounded deep analysis"},
            ])
        );
    }

    #[test]
    fn read_query_schema_exposes_direct_agent_surface() {
        let schema = schema_for(&["read_query"]);
        assert_eq!(schema["name"], json!("read_query"));
        assert_eq!(schema["subcommands"], json!([]));
        assert_eq!(
            schema["payload_contract"]["entrypoint"],
            json!("kura read_query")
        );
        assert!(
            schema["payload_contract"]["examples"][1]["payload"]["source_id"]
                == json!("performance_tests")
        );
        assert!(
            schema["args"]
                .as_array()
                .expect("args")
                .iter()
                .any(|arg| arg["id"] == json!("filters_json"))
        );
    }

    #[test]
    fn analyze_schema_exposes_direct_agent_surface() {
        let schema = schema_for(&["analyze"]);
        assert_eq!(schema["name"], json!("analyze"));
        assert_eq!(schema["subcommands"], json!([]));
        assert_eq!(
            schema["payload_contract"]["entrypoint"],
            json!("kura analyze")
        );
        assert!(
            schema["payload_contract"]["examples"][0]["payload"]["kernel"]["mode"]
                == json!("drivers")
        );
        assert!(
            schema["args"]
                .as_array()
                .expect("args")
                .iter()
                .any(|arg| arg["id"] == json!("kernel_json"))
        );
    }

    #[test]
    fn record_activity_schema_exposes_task_first_payload_contract() {
        let schema = schema_for(&["record_activity"]);
        assert_eq!(schema["name"], json!("record_activity"));
        assert_eq!(
            schema["payload_contract"]["entrypoint"],
            json!("kura record_activity")
        );
        assert_eq!(
            schema["payload_contract"]["endpoint"],
            json!("/v4/agent/record-activity")
        );
    }

    #[test]
    fn record_recovery_schema_exposes_task_first_payload_contract() {
        let schema = schema_for(&["record_recovery"]);
        assert_eq!(schema["name"], json!("record_recovery"));
        assert_eq!(
            schema["payload_contract"]["entrypoint"],
            json!("kura record_recovery")
        );
        assert_eq!(
            schema["payload_contract"]["endpoint"],
            json!("/v4/agent/record-recovery")
        );
        assert_eq!(
            schema["args"][0]["help"],
            json!("Inline JSON payload for one public task write")
        );
    }

    #[test]
    fn update_plan_schema_exposes_task_first_payload_contract() {
        let schema = schema_for(&["update_plan"]);
        assert_eq!(schema["name"], json!("update_plan"));
        assert_eq!(
            schema["payload_contract"]["entrypoint"],
            json!("kura update_plan")
        );
        assert_eq!(
            schema["payload_contract"]["endpoint"],
            json!("/v4/agent/update-plan")
        );
    }

    #[test]
    fn plan_activity_schema_exposes_task_first_payload_contract() {
        let schema = schema_for(&["plan_activity"]);
        assert_eq!(schema["name"], json!("plan_activity"));
        assert_eq!(
            schema["payload_contract"]["entrypoint"],
            json!("kura plan_activity")
        );
        assert_eq!(
            schema["payload_contract"]["endpoint"],
            json!("/v4/agent/plan-activity")
        );
    }

    #[test]
    fn dev_schema_collects_quarantined_root_surfaces() {
        let schema = schema_for(&["dev"]);
        assert_eq!(
            schema["subcommands"],
            json!([
                {"name": "health", "about": "Check API health"},
                {
                    "name": "api",
                    "about": "Direct API access (like gh api — works with any endpoint)"
                },
                {
                    "name": "exec",
                    "about": "Execute one request from a JSON envelope file (defaults to stdin)"
                },
                {
                    "name": "schema",
                    "about": "Emit machine-readable schema for CLI commands/args"
                },
                {"name": "event", "about": "Event operations (create, list, batch)"},
                {"name": "projection", "about": "Projection operations (get, list)"},
                {
                    "name": "agent",
                    "about": "Agent diagnostics, context, evidence, preferences, and visualization surfaces"
                },
                {
                    "name": "observation",
                    "about": "Observation workflows (draft visibility + promotion)"
                },
                {
                    "name": "mcp",
                    "about": "MCP server operations (Model Context Protocol over stdio)"
                },
                {"name": "import", "about": "External import job operations"},
                {"name": "provider", "about": "Provider connection operations"},
                {
                    "name": "eval",
                    "about": "Offline replay evaluation wrappers (worker-backed)"
                },
                {
                    "name": "snapshot",
                    "about": "Get all projections in one call (agent bootstrap snapshot)"
                },
                {
                    "name": "config",
                    "about": "Get system configuration (dimensions, conventions, event types)"
                },
                {"name": "doctor", "about": "Diagnose setup: API, auth, worker, system config"},
            ])
        );
    }

    #[test]
    fn admin_schema_collects_wrapped_specialist_surfaces() {
        let schema = schema_for(&["admin"]);
        assert_eq!(
            schema["subcommands"],
            json!([
                {"name": "access", "about": "Access request operations"},
                {"name": "account", "about": "Account operations"},
                {"name": "login", "about": "Authenticate with the Kura API via OAuth"},
                {"name": "logout", "about": "Remove stored credentials"},
                {
                    "name": "ops",
                    "about": "Specialist admin operations (bootstrapping and user management)"
                }
            ])
        );
    }

    #[test]
    fn update_profile_schema_exposes_task_first_payload_contract() {
        let schema = schema_for(&["update_profile"]);
        assert_eq!(schema["name"], json!("update_profile"));
        assert_eq!(
            schema["payload_contract"]["entrypoint"],
            json!("kura update_profile")
        );
        assert_eq!(
            schema["payload_contract"]["endpoint"],
            json!("/v4/agent/update-profile")
        );
    }
}
