use std::collections::{HashMap, HashSet};

use alphanumeric_sort::sort_str_slice;

use crate::{
    executables::{
        internal_executable::InternalExecutable,
        internal_executable_definition::{
            InternalExecutableDefinition, InternalExecutableDefinitionInput,
        },
    },
    logger::logger::Logger,
    validations::command_validations::CommandValidations,
};

pub struct ListOwners {
    pub definition: InternalExecutableDefinition,
}

impl ListOwners {
    pub fn new() -> ListOwners {
        ListOwners {
            definition: InternalExecutableDefinition::define(InternalExecutableDefinitionInput {
                name: "owners",
                description: "Lists all registered command owners",
                args: [],
            }),
        }
    }
}

impl InternalExecutable for ListOwners {
    fn run(&self, _: Vec<String>, _: &HashMap<String, Box<dyn InternalExecutable>>) {
        let registered_commands = CommandValidations::collect_and_validate_externals();
        Logger::info("Listing all command owners");
        let mut owners: HashSet<String> = HashSet::new();
        for (_, command) in registered_commands {
            if !command.owner.is_empty() {
                owners.insert(command.owner);
            }
        }
        if owners.is_empty() {
            return Logger::exit_with_info("No owners found");
        }
        let mut list: Vec<String> = owners.into_iter().collect();
        Logger::with_surrounding_space(|| {
            sort_str_slice(&mut list);
            for (index, owner) in list.iter().enumerate() {
                println!(
                    "{}{}",
                    Logger::indent(None),
                    Logger::cyan(format!("{}. {}", index + 1, &owner).as_str()),
                );
            }
        });
    }

    fn get_definition(&self) -> &InternalExecutableDefinition {
        &self.definition
    }
}
