use anyhow::{Context, Result};
use clap::Subcommand;
use std::collections::HashMap;
use std::sync::LazyLock;
#[derive(Subcommand)]
pub enum NatoAction {
#[command(about = "Encode text to NATO phonetic alphabet")]
Encode {
#[arg(help = "Input text")]
input: String,
},
#[command(about = "Decode NATO phonetic alphabet to text")]
Decode {
#[arg(help = "NATO phonetic words (space-separated)")]
input: String,
},
}
pub fn run(action: NatoAction) -> Result<()> {
match action {
NatoAction::Encode { input } => {
println!("{}", encode(&input));
}
NatoAction::Decode { input } => {
println!("{}", decode(&input)?);
}
}
Ok(())
}
const NATO_TABLE: &[(char, &str)] = &[
('A', "ALFA"),
('B', "BRAVO"),
('C', "CHARLIE"),
('D', "DELTA"),
('E', "ECHO"),
('F', "FOXTROT"),
('G', "GOLF"),
('H', "HOTEL"),
('I', "INDIA"),
('J', "JULIET"),
('K', "KILO"),
('L', "LIMA"),
('M', "MIKE"),
('N', "NOVEMBER"),
('O', "OSCAR"),
('P', "PAPA"),
('Q', "QUEBEC"),
('R', "ROMEO"),
('S', "SIERRA"),
('T', "TANGO"),
('U', "UNIFORM"),
('V', "VICTOR"),
('W', "WHISKEY"),
('X', "XRAY"),
('Y', "YANKEE"),
('Z', "ZULU"),
('0', "ZERO"),
('1', "ONE"),
('2', "TWO"),
('3', "THREE"),
('4', "FOUR"),
('5', "FIVE"),
('6', "SIX"),
('7', "SEVEN"),
('8', "EIGHT"),
('9', "NINE"),
];
static CHAR_TO_NATO: LazyLock<HashMap<char, &'static str>> =
LazyLock::new(|| NATO_TABLE.iter().copied().collect());
static NATO_TO_CHAR: LazyLock<HashMap<&'static str, char>> =
LazyLock::new(|| NATO_TABLE.iter().map(|&(c, word)| (word, c)).collect());
pub fn encode(input: &str) -> String {
input
.to_uppercase()
.chars()
.filter_map(|c| CHAR_TO_NATO.get(&c).copied())
.collect::<Vec<_>>()
.join(" ")
}
pub fn decode(input: &str) -> Result<String> {
if input.trim().is_empty() {
return Ok(String::new());
}
input
.split_whitespace()
.map(|word| {
let upper = word.to_uppercase();
NATO_TO_CHAR
.get(upper.as_str())
.copied()
.context(format!("Unknown NATO word: {}", word))
})
.collect::<Result<String>>()
}