use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;

use crate::error::CliError;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CommandEntry {
    pub command: String,
    #[serde(default)]
    pub aliases: Vec<String>,
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub requires_args: bool,
    #[serde(default)]
    pub requires_daemon: bool,
    #[serde(default)]
    pub help_category: String,
    #[serde(default)]
    pub daemon_target: DaemonTarget,
}

#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum DaemonTarget {
    #[default]
    None,
    Cli,
    Orchestrator,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Registry {
    pub commands: Vec<CommandEntry>,
}

impl Registry {
    pub fn from_json(path: &Path) -> Result<Self, CliError> {
        let content = std::fs::read_to_string(path)?;
        serde_json::from_str(&content).map_err(|e| CliError::CacheParse(e.to_string()))
    }

    /// Build a lookup map: canonical name + all aliases → CommandEntry
    pub fn into_index(self) -> HashMap<String, CommandEntry> {
        let mut map = HashMap::with_capacity(self.commands.len() * 3);
        for entry in self.commands {
            map.insert(entry.command.clone(), entry.clone());
            for alias in &entry.aliases {
                map.insert(alias.clone(), entry.clone());
            }
        }
        map
    }
}

#[derive(Debug, Serialize)]
pub struct LookupResult {
    pub found: bool,
    pub command: Option<String>,
    pub description: Option<String>,
    pub requires_args: bool,
    pub requires_daemon: bool,
    pub help_category: Option<String>,
    pub daemon_target: Option<String>,
}

impl LookupResult {
    pub fn not_found() -> Self {
        Self {
            found: false,
            command: None,
            description: None,
            requires_args: false,
            requires_daemon: false,
            help_category: None,
            daemon_target: None,
        }
    }

    pub fn from_entry(entry: &CommandEntry) -> Self {
        Self {
            found: true,
            command: Some(entry.command.clone()),
            description: Some(entry.description.clone()),
            requires_args: entry.requires_args,
            requires_daemon: entry.requires_daemon,
            help_category: Some(entry.help_category.clone()),
            daemon_target: Some(format!("{:?}", entry.daemon_target).to_lowercase()),
        }
    }
}
