//! `status` command -- report WAL state, checkpoint, and directory layout.

use serde::Serialize;

use crate::{
    CliError, EXIT_DEGRADED,
    commands::paths::DirsOutput,
    json::render_json,
    wal_state::{WalState, gather_wal_state},
};

/// `status` command output.
///
/// `wal` carries the gathered [`WalState`] on success, or an `{"error": ...}`
/// envelope when the WAL could not be inspected — modeled as an untagged enum
/// so serde emits exactly one of the two shapes without a discriminant tag.
#[derive(Serialize)]
struct StatusOutput<'a> {
    version: &'a str,
    build_hash: &'a str,
    status: &'a str,
    wal: WalField,
    dirs: DirsOutput,
}

#[derive(Serialize)]
#[serde(untagged)]
enum WalField {
    State(WalState),
    Error { error: String },
}

pub(crate) fn run(base: &std::path::Path, pretty: bool) -> Result<(String, i32), CliError> {
    let paths = tidaldb::Paths::new(base);
    let wal_dir = paths.wal_dir();

    let version = env!("CARGO_PKG_VERSION");
    let build_hash = tidaldb::BUILD_HASH;

    // Determine WAL state.
    let wal_result = gather_wal_state(&wal_dir);

    // An unreadable WAL (directory present but segments/checkpoint can't be
    // read) is degraded, not a clean empty store: exit code 2, mirroring
    // `diagnostics`. A script using `tidalctl status --path X && deploy` must
    // not treat a corrupt WAL as success.
    let (status, wal, exit_code) = match wal_result {
        Ok(wal) if wal.segments > 0 => ("ok", WalField::State(wal), 0),
        Ok(wal) => ("empty", WalField::State(wal), 0),
        Err(e) => ("error", WalField::Error { error: e }, EXIT_DEGRADED),
    };

    let output = StatusOutput {
        version,
        build_hash,
        status,
        wal,
        dirs: DirsOutput::new(&paths),
    };

    let rendered = render_json(&output, pretty)?;
    Ok((rendered, exit_code))
}
