//! CLI Backend using inquire for interactive prompts
//!
//! This backend provides the existing inquire-based CLI interface.
//! It will be the primary implementation of FormBackend for terminal-based forms.

use super::{FormBackend, RenderContext};
use crate::error::Result;
use crate::form_parser::{DisplayItem, FieldDefinition, FieldType, SelectOption};
use crate::prompts;
use async_trait::async_trait;
use serde_json::Value;
use std::collections::HashMap;

pub(crate) fn filter_options_from(
    field: &FieldDefinition,
    previous_results: &HashMap<String, Value>,
) -> Vec<SelectOption> {
    let Some(ref source_field) = field.options_from else {
        return field.options.clone();
    };
    let Some(source_value) = previous_results.get(source_field) else {
        return field.options.clone();
    };
    let selected_values: Vec<String> = match source_value {
        Value::Array(arr) => arr
            .iter()
            .filter_map(|v| v.as_str().map(str::to_owned))
            .collect(),
        Value::String(s) => s.split(',').map(|item| item.trim().to_owned()).collect(),
        _ => return field.options.clone(),
    };
    field
        .options
        .iter()
        .filter(|opt| selected_values.contains(&opt.value))
        .cloned()
        .collect()
}

/// CLI Backend implementation using inquire
pub struct InquireBackend;

impl InquireBackend {
    /// Create a new CLI backend instance
    pub fn new() -> Self {
        InquireBackend
    }

    pub(crate) fn execute_field_sync(
        &self,
        field: &FieldDefinition,
        previous_results: &HashMap<String, Value>,
    ) -> Result<Value> {
        let is_required = field.required.unwrap_or(false);
        let required_marker = if is_required { " *" } else { " (optional)" };

        loop {
            match field.field_type {
                FieldType::Text => {
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let result = prompts::text(
                        &prompt_with_marker,
                        field.default.as_deref(),
                        field.placeholder.as_deref(),
                    )?;

                    if is_required && result.is_empty() {
                        eprintln!("⚠ This field is required. Please enter a value.");
                        continue;
                    }
                    return Ok(serde_json::json!(result));
                }

                FieldType::Confirm => {
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let default_bool =
                        field
                            .default
                            .as_deref()
                            .and_then(|s| match s.to_lowercase().as_str() {
                                "true" | "yes" => Some(true),
                                "false" | "no" => Some(false),
                                _ => None,
                            });
                    let result = prompts::confirm(&prompt_with_marker, default_bool, None)?;
                    return Ok(serde_json::json!(result));
                }

                FieldType::Password => {
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let with_toggle = field.placeholder.as_deref() == Some("toggle");
                    let result = prompts::password(&prompt_with_marker, with_toggle)?;

                    if is_required && result.is_empty() {
                        eprintln!("⚠ This field is required. Please enter a value.");
                        continue;
                    }
                    return Ok(serde_json::json!(result));
                }

                FieldType::Select => {
                    if field.options.is_empty() {
                        return Err(crate::ErrorWrapper::form_parse_failed(
                            "Select field requires 'options'",
                        ));
                    }
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let filtered = filter_options_from(field, previous_results);
                    if filtered.is_empty() {
                        return Err(crate::ErrorWrapper::form_parse_failed(format!(
                            "No options available for field '{}'. Check options_from reference.",
                            field.name
                        )));
                    }
                    let options = filtered
                        .iter()
                        .map(|opt| opt.as_string())
                        .collect::<Vec<_>>();
                    let result = prompts::select(
                        &prompt_with_marker,
                        options,
                        field.page_size,
                        field.vim_mode.unwrap_or(false),
                    )?;
                    return Ok(serde_json::json!(result));
                }

                FieldType::MultiSelect => {
                    if field.options.is_empty() {
                        return Err(crate::ErrorWrapper::form_parse_failed(
                            "MultiSelect field requires 'options'",
                        ));
                    }
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let options = field
                        .options
                        .iter()
                        .map(|opt| opt.as_string())
                        .collect::<Vec<_>>();
                    let results = prompts::multi_select(
                        &prompt_with_marker,
                        options,
                        field.page_size,
                        field.vim_mode.unwrap_or(false),
                    )?;

                    if is_required && results.is_empty() {
                        eprintln!("⚠ This field is required. Please select at least one option.");
                        continue;
                    }
                    return Ok(serde_json::json!(results));
                }

                FieldType::Editor => {
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let result = prompts::editor(
                        &prompt_with_marker,
                        field.file_extension.as_deref(),
                        field.prefix_text.as_deref(),
                    )?;

                    if is_required && result.is_empty() {
                        eprintln!("⚠ This field is required. Please enter a value.");
                        continue;
                    }
                    return Ok(serde_json::json!(result));
                }

                FieldType::Date => {
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let week_start = field.week_start.as_deref().unwrap_or("Mon");
                    let result = prompts::date(
                        &prompt_with_marker,
                        field.default.as_deref(),
                        field.min_date.as_deref(),
                        field.max_date.as_deref(),
                        week_start,
                    )?;
                    return Ok(serde_json::json!(result));
                }

                FieldType::Custom => {
                    let prompt_with_marker = format!("{}{}", field.prompt, required_marker);
                    let type_name = field.custom_type.as_ref().ok_or_else(|| {
                        crate::ErrorWrapper::form_parse_failed(
                            "Custom field requires 'custom_type'",
                        )
                    })?;
                    let result =
                        prompts::custom(&prompt_with_marker, type_name, field.default.as_deref())?;

                    if is_required && result.is_empty() {
                        eprintln!("⚠ This field is required. Please enter a value.");
                        continue;
                    }
                    return Ok(serde_json::json!(result));
                }

                FieldType::RepeatingGroup => {
                    let fragment_path = field.fragment.as_ref().ok_or_else(|| {
                        crate::ErrorWrapper::form_parse_failed(
                            "RepeatingGroup requires 'fragment' field",
                        )
                    })?;
                    return self.execute_repeating_group(field, fragment_path);
                }
            }
        }
    }

    /// Execute a repeating group field with interactive add/edit/delete menu
    fn execute_repeating_group(
        &self,
        field: &FieldDefinition,
        fragment_path: &str,
    ) -> Result<Value> {
        let min_items = field.min_items.unwrap_or(0);
        let max_items = field.max_items.unwrap_or(usize::MAX);
        let default_items = field.default_items.unwrap_or(0);

        let mut items: Vec<HashMap<String, Value>> = Vec::new();

        // Pre-populate with default_items empty entries if requested
        for _ in 0..default_items {
            // Start with empty items - user can edit them
        }

        loop {
            // Build menu options based on current state
            let options = Self::build_array_menu_options(&items, min_items, max_items);

            let status_msg = if min_items > 0 && items.len() < min_items {
                format!(" - minimum {} required", min_items)
            } else {
                String::new()
            };

            let prompt = format!(
                "{} ({} items configured){}",
                field.prompt,
                items.len(),
                status_msg
            );

            let choice = prompts::select(&prompt, options, None, false)?;

            match choice.as_str() {
                "[A] Add new item" => {
                    if items.len() >= max_items {
                        eprintln!("⚠ Maximum {} items reached", max_items);
                        continue;
                    }

                    match Self::execute_fragment(fragment_path, items.len() + 1) {
                        Ok(item_data) => {
                            // Check for duplicates if unique constraint is set
                            if field.unique.unwrap_or(false)
                                && Self::is_duplicate(&item_data, &items, None, field)
                            {
                                eprintln!("⚠ This item already exists. Duplicates not allowed.");
                                continue;
                            }
                            items.push(item_data);
                            println!("✓ Item added successfully");
                        }
                        Err(e) => {
                            eprintln!("⚠ Error adding item: {}", e);
                        }
                    }
                }
                "[E] Edit item" => match Self::select_item_to_edit(&items) {
                    Ok(index) => match Self::execute_fragment(fragment_path, index + 1) {
                        Ok(updated_data) => {
                            // Check for duplicates if unique constraint is set (exclude current item)
                            if field.unique.unwrap_or(false)
                                && Self::is_duplicate(&updated_data, &items, Some(index), field)
                            {
                                eprintln!("⚠ This item already exists. Duplicates not allowed.");
                                continue;
                            }
                            items[index] = updated_data;
                            println!("✓ Item updated successfully");
                        }
                        Err(e) => {
                            eprintln!("⚠ Error editing item: {}", e);
                        }
                    },
                    Err(e) => {
                        eprintln!("⚠ {}", e);
                    }
                },
                "[D] Delete item" => match Self::select_item_to_delete(&items) {
                    Ok(index) => {
                        items.remove(index);
                        println!("✓ Item #{} deleted", index + 1);
                    }
                    Err(e) => {
                        eprintln!("⚠ {}", e);
                    }
                },
                "[C] Continue to next field" => {
                    if items.len() < min_items {
                        eprintln!("⚠ Minimum {} items required", min_items);
                        continue;
                    }
                    break;
                }
                _ => {}
            }
        }

        Ok(serde_json::json!(items))
    }

    /// Build menu options for array management
    fn build_array_menu_options(
        items: &[HashMap<String, Value>],
        min_items: usize,
        max_items: usize,
    ) -> Vec<String> {
        let mut options = Vec::new();

        if items.len() < max_items {
            options.push("[A] Add new item".to_string());
        }

        if !items.is_empty() {
            options.push("[E] Edit item".to_string());
            options.push("[D] Delete item".to_string());
        }

        if items.len() >= min_items {
            options.push("[C] Continue to next field".to_string());
        }

        options
    }

    /// Execute a fragment to collect data for one array item
    fn execute_fragment(fragment_path: &str, item_number: usize) -> Result<HashMap<String, Value>> {
        // Load fragment TOML
        let fragment_form = crate::form_parser::load_fragment_form(fragment_path)?;

        println!("\n--- Item #{} ---", item_number);

        // Execute each field in fragment
        let mut results = HashMap::new();
        let backend = InquireBackend::new();

        for element in &fragment_form.elements {
            if let crate::form_parser::FormElement::Field(field_def) = element {
                let value = backend.execute_field_sync(field_def, &results)?;
                results.insert(field_def.name.clone(), value);
            }
        }

        Ok(results)
    }

    /// Select an item to edit from the list
    fn select_item_to_edit(items: &[HashMap<String, Value>]) -> Result<usize> {
        if items.is_empty() {
            return Err(crate::ErrorWrapper::form_parse_failed("No items to edit"));
        }

        let labels: Vec<String> = items
            .iter()
            .enumerate()
            .map(|(i, item)| format!("Item #{} - {}", i + 1, Self::summarize_item(item)))
            .collect();

        let choice = prompts::select("Select item to edit", labels, None, false)?;

        // Extract index from choice (format: "Item #N - ...")
        let index_str = choice
            .split('#')
            .nth(1)
            .and_then(|s| s.split('-').next())
            .and_then(|s| s.trim().parse::<usize>().ok())
            .ok_or_else(|| crate::ErrorWrapper::form_parse_failed("Failed to parse item index"))?;

        Ok(index_str - 1) // Convert to 0-indexed
    }

    /// Select an item to delete from the list
    fn select_item_to_delete(items: &[HashMap<String, Value>]) -> Result<usize> {
        if items.is_empty() {
            return Err(crate::ErrorWrapper::form_parse_failed("No items to delete"));
        }

        let labels: Vec<String> = items
            .iter()
            .enumerate()
            .map(|(i, item)| format!("Item #{} - {}", i + 1, Self::summarize_item(item)))
            .collect();

        let choice = prompts::select("Select item to delete", labels, None, false)?;

        // Extract index from choice (format: "Item #N - ...")
        let index_str = choice
            .split('#')
            .nth(1)
            .and_then(|s| s.split('-').next())
            .and_then(|s| s.trim().parse::<usize>().ok())
            .ok_or_else(|| crate::ErrorWrapper::form_parse_failed("Failed to parse item index"))?;

        Ok(index_str - 1) // Convert to 0-indexed
    }

    /// Summarize an item for display in lists
    fn summarize_item(item: &HashMap<String, Value>) -> String {
        // Try to find a meaningful field to display (first string field, or first field)
        if let Some(first_string) = item.values().find_map(|v| v.as_str()) {
            first_string.chars().take(40).collect()
        } else if let Some(first_value) = item.values().next() {
            format!("{:?}", first_value).chars().take(40).collect()
        } else {
            "(empty)".to_string()
        }
    }

    /// Check if a new item is a duplicate of existing items
    fn is_duplicate(
        new_item: &HashMap<String, Value>,
        items: &[HashMap<String, Value>],
        exclude_index: Option<usize>,
        field: &FieldDefinition,
    ) -> bool {
        let has_unique = field.unique.unwrap_or(false);

        for (idx, existing_item) in items.iter().enumerate() {
            // Skip comparing with self when editing
            if let Some(exclude_idx) = exclude_index {
                if idx == exclude_idx {
                    continue;
                }
            }

            if has_unique {
                // Check if ALL fields match
                let all_match = new_item
                    .iter()
                    .all(|(key, value)| existing_item.get(key) == Some(value));

                if all_match && !new_item.is_empty() {
                    return true;
                }
            }
        }

        false
    }
}

impl Default for InquireBackend {
    fn default() -> Self {
        Self::new()
    }
}

#[async_trait]
impl FormBackend for InquireBackend {
    async fn initialize(&mut self) -> Result<()> {
        // No initialization needed for CLI backend
        Ok(())
    }

    async fn render_display_item(&self, item: &DisplayItem, context: &RenderContext) -> Result<()> {
        crate::form_parser::render_display_item(item, &context.results);
        Ok(())
    }

    async fn execute_field(
        &self,
        field: &FieldDefinition,
        context: &RenderContext,
    ) -> Result<Value> {
        self.execute_field_sync(field, &context.results)
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }

    async fn shutdown(&mut self) -> Result<()> {
        // No cleanup needed for CLI backend
        Ok(())
    }

    fn is_available() -> bool {
        // CLI backend is always available
        true
    }

    fn name(&self) -> &str {
        "cli"
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_inquire_backend_new() {
        let backend = InquireBackend::new();
        assert_eq!(backend.name(), "cli");
    }

    #[test]
    fn test_inquire_backend_available() {
        assert!(InquireBackend::is_available());
    }

    #[test]
    fn test_inquire_backend_default() {
        let backend = InquireBackend;
        assert_eq!(backend.name(), "cli");
    }

    #[tokio::test]
    async fn test_inquire_backend_lifecycle() {
        let mut backend = InquireBackend::new();
        assert!(backend.initialize().await.is_ok());
        assert!(backend.shutdown().await.is_ok());
    }
}
