//! Form widget for user input and validation
//!
//! Implements R-WIDGET-COMPOSITION and R-STATE-SEPARATION:
//! - Form state separate from rendering
//! - Support for multiple input field types
//! - Built-in validation
//! - Theme-aware styling

use crate::config::Theme;
use ratatui::prelude::*;
use ratatui::widgets::{Block, Borders, Paragraph};

/// Field type for form inputs
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FieldType {
    /// Single-line text input
    Text,
    /// Multi-line text input
    TextArea,
    /// Number input
    Number,
    /// Select from options
    Select(Vec<String>),
    /// Toggle boolean
    Toggle,
}

/// Validation result with optional error message
pub type ValidationResult = Result<(), String>;

/// Validation function type
pub type ValidatorFn = fn(&str) -> ValidationResult;

/// A single form field
///
/// # Example
///
/// ```ignore
/// let field = FormField::new("name".to_string(), FieldType::Text)
///     .with_label("Your Name")
///     .with_required(true)
///     .with_validator(|s| {
///         if s.is_empty() { Err("Name required".to_string()) }
///         else { Ok(()) }
///     });
/// ```
#[derive(Clone, Debug)]
pub struct FormField {
    /// Field identifier
    id: String,
    /// Field display label
    label: String,
    /// Field type
    field_type: FieldType,
    /// Current value
    value: String,
    /// Field is required
    required: bool,
    /// Field validation error (if any)
    error: Option<String>,
    /// Placeholder text
    placeholder: Option<String>,
}

impl FormField {
    /// Create a new form field
    #[must_use]
    pub fn new(id: String, field_type: FieldType) -> Self {
        Self {
            label: id.clone(),
            id,
            field_type,
            value: String::new(),
            required: false,
            error: None,
            placeholder: None,
        }
    }

    /// Set the display label
    #[must_use]
    pub fn with_label(mut self, label: &str) -> Self {
        self.label = label.to_string();
        self
    }

    /// Set as required field
    #[must_use]
    pub const fn with_required(mut self, required: bool) -> Self {
        self.required = required;
        self
    }

    /// Set placeholder text
    #[must_use]
    pub fn with_placeholder(mut self, placeholder: &str) -> Self {
        self.placeholder = Some(placeholder.to_string());
        self
    }

    /// Get field ID
    #[must_use]
    pub fn id(&self) -> &str {
        &self.id
    }

    /// Get field label
    #[must_use]
    pub fn label(&self) -> &str {
        &self.label
    }

    /// Get field type
    #[must_use]
    pub const fn field_type(&self) -> &FieldType {
        &self.field_type
    }

    /// Get current value
    #[must_use]
    pub fn value(&self) -> &str {
        &self.value
    }

    /// Set field value
    pub fn set_value(&mut self, value: String) {
        self.value = value;
        self.error = None;
    }

    /// Check if field is required
    #[must_use]
    pub const fn is_required(&self) -> bool {
        self.required
    }

    /// Get validation error if present
    #[must_use]
    pub fn error(&self) -> Option<&str> {
        self.error.as_deref()
    }

    /// Set validation error
    pub fn set_error(&mut self, error: String) {
        self.error = Some(error);
    }

    /// Clear validation error
    pub fn clear_error(&mut self) {
        self.error = None;
    }

    /// Validate field value
    ///
    /// # Errors
    /// Returns an error if validation fails with a descriptive error message.
    pub fn validate(&mut self) -> ValidationResult {
        self.clear_error();

        if self.required && self.value.is_empty() {
            let msg = format!("{} is required", self.label);
            self.set_error(msg.clone());
            return Err(msg);
        }

        Ok(())
    }

    /// Get placeholder text
    #[must_use]
    pub fn placeholder(&self) -> Option<&str> {
        self.placeholder.as_deref()
    }
}

impl PartialEq for FormField {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id && self.value == other.value
    }
}

impl Eq for FormField {}

/// Form widget managing multiple fields
///
/// Implements R-STATE-SEPARATION: Form state is held separately
/// from rendering logic.
///
/// # Example
///
/// ```ignore
/// let mut form = Form::new()
///     .add_field(FormField::new("name".to_string(), FieldType::Text)
///         .with_label("Name")
///         .with_required(true))
///     .add_field(FormField::new("email".to_string(), FieldType::Text)
///         .with_label("Email")
///         .with_required(true));
///
/// form.focus_next();
/// form.render(&theme, frame, area);
/// ```
#[derive(Clone, Debug)]
pub struct Form {
    /// Form fields
    fields: Vec<FormField>,
    /// Currently focused field index
    focused: usize,
    /// Dirty flag for efficient rendering
    dirty: bool,
}

impl Form {
    /// Create a new empty form
    #[must_use]
    pub const fn new() -> Self {
        Self {
            fields: Vec::new(),
            focused: 0,
            dirty: true,
        }
    }

    /// Add a field to the form
    #[must_use]
    pub fn add_field(mut self, field: FormField) -> Self {
        self.fields.push(field);
        self.dirty = true;
        self
    }

    /// Get the number of fields
    #[must_use]
    pub const fn len(&self) -> usize {
        self.fields.len()
    }

    /// Check if form is empty
    #[must_use]
    pub const fn is_empty(&self) -> bool {
        self.fields.is_empty()
    }

    /// Get currently focused field
    #[must_use]
    pub fn focused_field(&self) -> Option<&FormField> {
        if self.focused < self.fields.len() {
            Some(&self.fields[self.focused])
        } else {
            None
        }
    }

    /// Get mutable reference to currently focused field
    pub fn focused_field_mut(&mut self) -> Option<&mut FormField> {
        if self.focused < self.fields.len() {
            Some(&mut self.fields[self.focused])
        } else {
            None
        }
    }

    /// Get index of focused field
    #[must_use]
    pub const fn focused_index(&self) -> usize {
        self.focused
    }

    /// Move focus to next field
    pub const fn focus_next(&mut self) {
        if !self.fields.is_empty() {
            self.focused = (self.focused + 1) % self.fields.len();
            self.dirty = true;
        }
    }

    /// Move focus to previous field
    pub const fn focus_previous(&mut self) {
        if !self.fields.is_empty() {
            self.focused = if self.focused == 0 {
                self.fields.len() - 1
            } else {
                self.focused - 1
            };
            self.dirty = true;
        }
    }

    /// Set focus to specific field by index
    pub const fn set_focus(&mut self, index: usize) {
        if index < self.fields.len() {
            self.focused = index;
            self.dirty = true;
        }
    }

    /// Get all fields
    #[must_use]
    pub fn fields(&self) -> &[FormField] {
        &self.fields
    }

    /// Get mutable reference to all fields
    pub const fn fields_mut(&mut self) -> &mut Vec<FormField> {
        self.dirty = true;
        &mut self.fields
    }

    /// Get field value by ID
    #[must_use]
    pub fn get_value(&self, field_id: &str) -> Option<String> {
        self.fields
            .iter()
            .find(|f| f.id() == field_id)
            .map(|f| f.value().to_string())
    }

    /// Set field value by ID
    pub fn set_value(&mut self, field_id: &str, value: String) {
        if let Some(field) = self.fields.iter_mut().find(|f| f.id() == field_id) {
            field.set_value(value);
            self.dirty = true;
        }
    }

    /// Validate all fields
    ///
    /// # Errors
    /// Returns an error if any field validation fails.
    pub fn validate(&mut self) -> ValidationResult {
        let mut errors = Vec::new();

        for field in &mut self.fields {
            if let Err(e) = field.validate() {
                errors.push(e);
            }
        }

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors.join("; "))
        }
    }

    /// Get all values as a map
    #[must_use]
    pub fn values(&self) -> std::collections::HashMap<String, String> {
        self.fields
            .iter()
            .map(|f| (f.id().to_string(), f.value().to_string()))
            .collect()
    }

    /// Check if state has changed since last render
    #[must_use]
    pub const fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Reset dirty flag after rendering
    pub const fn reset_dirty(&mut self) {
        self.dirty = false;
    }

    /// Render the form using the given theme
    pub fn render(&mut self, theme: &Theme, frame: &mut Frame, area: Rect) {
        if area.height < 1 || self.fields.is_empty() {
            return;
        }

        let field_height = 3; // Label + input + spacing
        let max_fields = (area.height as usize / field_height).max(1);

        let mut lines = Vec::new();

        for (idx, field) in self.fields.iter().take(max_fields).enumerate() {
            let is_focused = idx == self.focused;
            let style = if is_focused {
                theme.focused_style()
            } else {
                theme.normal_style()
            };

            // Label line
            let label_line = Line::from(Span::styled(format!("{}: ", field.label()), style));
            lines.push(label_line);

            // Value line
            let value_text = if field.value().is_empty() {
                field.placeholder().unwrap_or("").to_string()
            } else {
                field.value().to_string()
            };

            let value_style = if field.error().is_some() {
                theme.error_style()
            } else if is_focused {
                theme.selected_style()
            } else {
                theme.normal_style()
            };

            let value_line = Line::from(Span::styled(value_text, value_style));
            lines.push(value_line);

            // Error line if present
            if let Some(error) = field.error() {
                let error_line =
                    Line::from(Span::styled(format!("  ⚠ {error}"), theme.error_style()));
                lines.push(error_line);
            } else {
                lines.push(Line::from("")); // Spacing
            }
        }

        let paragraph = Paragraph::new(lines)
            .block(
                Block::default()
                    .title("Form")
                    .borders(Borders::ALL)
                    .border_style(theme.focused_style()),
            )
            .style(theme.normal_style());

        frame.render_widget(paragraph, area);
        self.reset_dirty();
    }
}

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

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

    #[test]
    fn test_form_field_new() {
        let field = FormField::new("email".to_string(), FieldType::Text);
        assert_eq!(field.id(), "email");
        assert_eq!(field.label(), "email");
        assert_eq!(field.value(), "");
        assert!(!field.is_required());
        assert_eq!(field.error(), None);
    }

    #[test]
    fn test_form_field_label() {
        let field =
            FormField::new("email".to_string(), FieldType::Text).with_label("Email Address");
        assert_eq!(field.label(), "Email Address");
    }

    #[test]
    fn test_form_field_required() {
        let field = FormField::new("password".to_string(), FieldType::Text).with_required(true);
        assert!(field.is_required());
    }

    #[test]
    fn test_form_field_placeholder() {
        let field =
            FormField::new("name".to_string(), FieldType::Text).with_placeholder("Enter your name");
        assert_eq!(field.placeholder(), Some("Enter your name"));
    }

    #[test]
    fn test_form_field_set_value() {
        let mut field = FormField::new("name".to_string(), FieldType::Text);
        field.set_value("John".to_string());
        assert_eq!(field.value(), "John");
    }

    #[test]
    fn test_form_field_validate_required() {
        let mut field = FormField::new("name".to_string(), FieldType::Text).with_required(true);

        let result = field.validate();
        assert!(result.is_err());
        assert!(field.error().is_some());
    }

    #[test]
    fn test_form_field_validate_required_pass() {
        let mut field = FormField::new("name".to_string(), FieldType::Text).with_required(true);
        field.set_value("John".to_string());

        let result = field.validate();
        assert!(result.is_ok());
        assert_eq!(field.error(), None);
    }

    #[test]
    fn test_form_field_clear_error() {
        let mut field = FormField::new("name".to_string(), FieldType::Text);
        field.set_error("Test error".to_string());
        assert!(field.error().is_some());

        field.clear_error();
        assert_eq!(field.error(), None);
    }

    #[test]
    fn test_form_field_clone() {
        let field1 = FormField::new("name".to_string(), FieldType::Text);
        let field2 = field1.clone();
        assert_eq!(field1.id(), field2.id());
    }

    #[test]
    fn test_form_new() {
        let form = Form::new();
        assert!(form.is_empty());
        assert_eq!(form.len(), 0);
    }

    #[test]
    fn test_form_add_field() {
        let field1 = FormField::new("name".to_string(), FieldType::Text);
        let field2 = FormField::new("email".to_string(), FieldType::Text);

        let form = Form::new().add_field(field1).add_field(field2);

        assert_eq!(form.len(), 2);
        assert!(!form.is_empty());
    }

    #[test]
    fn test_form_focused_field() {
        let field = FormField::new("name".to_string(), FieldType::Text);
        let form = Form::new().add_field(field);

        let focused = form.focused_field();
        assert!(focused.is_some());
        assert_eq!(focused.unwrap().id(), "name");
    }

    #[test]
    fn test_form_focus_next() {
        let form = Form::new()
            .add_field(FormField::new("name".to_string(), FieldType::Text))
            .add_field(FormField::new("email".to_string(), FieldType::Text))
            .add_field(FormField::new("password".to_string(), FieldType::Text));

        let mut form = form;
        assert_eq!(form.focused_index(), 0);

        form.focus_next();
        assert_eq!(form.focused_index(), 1);

        form.focus_next();
        assert_eq!(form.focused_index(), 2);

        form.focus_next();
        assert_eq!(form.focused_index(), 0); // Wraps
    }

    #[test]
    fn test_form_focus_previous() {
        let mut form = Form::new()
            .add_field(FormField::new("name".to_string(), FieldType::Text))
            .add_field(FormField::new("email".to_string(), FieldType::Text));

        form.set_focus(1);
        form.focus_previous();
        assert_eq!(form.focused_index(), 0);
    }

    #[test]
    fn test_form_set_focus() {
        let mut form = Form::new()
            .add_field(FormField::new("name".to_string(), FieldType::Text))
            .add_field(FormField::new("email".to_string(), FieldType::Text));

        form.set_focus(1);
        assert_eq!(form.focused_index(), 1);
    }

    #[test]
    fn test_form_get_value() {
        let mut form = Form::new().add_field(FormField::new("name".to_string(), FieldType::Text));

        form.set_value("name", "John".to_string());
        assert_eq!(form.get_value("name"), Some("John".to_string()));
    }

    #[test]
    fn test_form_validate() {
        let mut form = Form::new()
            .add_field(FormField::new("name".to_string(), FieldType::Text).with_required(true))
            .add_field(FormField::new("email".to_string(), FieldType::Text).with_required(true));

        let result = form.validate();
        assert!(result.is_err());
    }

    #[test]
    fn test_form_validate_pass() {
        let mut form = Form::new()
            .add_field(FormField::new("name".to_string(), FieldType::Text).with_required(true))
            .add_field(FormField::new("email".to_string(), FieldType::Text).with_required(true));

        form.set_value("name", "John".to_string());
        form.set_value("email", "john@example.com".to_string());

        let result = form.validate();
        assert!(result.is_ok());
    }

    #[test]
    fn test_form_values() {
        let mut form = Form::new()
            .add_field(FormField::new("name".to_string(), FieldType::Text))
            .add_field(FormField::new("email".to_string(), FieldType::Text));

        form.set_value("name", "John".to_string());
        form.set_value("email", "john@example.com".to_string());

        let values = form.values();
        assert_eq!(values.get("name"), Some(&"John".to_string()));
        assert_eq!(values.get("email"), Some(&"john@example.com".to_string()));
    }

    #[test]
    fn test_form_dirty_flag() {
        let mut form = Form::new().add_field(FormField::new("name".to_string(), FieldType::Text));

        assert!(form.is_dirty());
        form.reset_dirty();
        assert!(!form.is_dirty());

        form.focus_next();
        assert!(form.is_dirty());
    }

    #[test]
    fn test_form_default() {
        let form = Form::default();
        assert!(form.is_empty());
    }
}
