///|
/// Editable components - Integrates display components with editing functionality

///|
/// Configuration for editable input behavior
pub(all) struct EditConfig {
  /// Field name displayed during editing
  field_name : String
  /// Called when value is confirmed
  on_change : (String) -> Unit
  /// Called before editing starts (optional, for setup like disabling mouse)
  on_edit_start : (() -> Unit)?
  /// Called after editing ends (optional, for cleanup like re-enabling mouse)
  on_edit_end : (() -> Unit)?
  /// Called when Ctrl+C is pressed (optional, for force quit)
  on_force_quit : (() -> Unit)?
}

///|
/// Start editing a field with cooked mode (IME support)
/// This exits alternate screen temporarily for proper IME input
/// confirm_on_shift_enter: if true, Shift+Enter confirms and Enter inserts newline
/// esc_cancels: if false, Esc is ignored
pub fn start_edit(
  config : EditConfig,
  current_value : String,
  on_complete : () -> Unit,
  confirm_on_shift_enter? : Bool = false,
  esc_cancels? : Bool = true,
) -> Unit {
  // Call optional setup callback
  match config.on_edit_start {
    Some(f) => f()
    None => ()
  }

  // Start cooked mode input
  @io.start_inline_input_cooked(
    config.field_name,
    current_value,
    fn(result) {
      match result {
        @io.InputResult::Confirmed(new_value) => (config.on_change)(new_value)
        @io.InputResult::Cancelled => ()
        @io.InputResult::ForceQuit => {
          // Call force quit handler if provided
          match config.on_force_quit {
            Some(f) => f()
            None => ()
          }
          // Don't call on_complete - we're quitting
          return
        }
        _ => ()
      }

      // Call optional cleanup callback
      match config.on_edit_end {
        Some(f) => f()
        None => ()
      }
      on_complete()
    },
    confirm_on_shift_enter~,
    esc_cancels~,
  )
}

///|
/// Start editing a field inplace (stays in TUI screen)
/// row/col are 1-indexed ANSI coordinates
/// width/height define the input area (supports multi-line wrapping)
/// multiline: if true, Enter can insert newline when confirm_on_shift_enter is true
/// confirm_on_shift_enter: if true, Shift+Enter confirms
/// esc_cancels: if false, Esc is ignored
/// on_lines_change: optional callback (line_count) -> new_height for dynamic resizing
/// on_completion: optional callback (text, cursor_pos) -> completion_suffix for Tab completion
pub fn start_edit_inplace(
  config : EditConfig,
  current_value : String,
  row : Int,
  col : Int,
  width : Int,
  height : Int,
  multiline : Bool,
  on_complete : () -> Unit,
  confirm_on_shift_enter? : Bool = false,
  esc_cancels? : Bool = true,
  on_lines_change? : ((Int) -> Int)? = None,
  on_completion? : ((String, Int) -> String?)? = None,
) -> Unit {
  // Call optional setup callback
  match config.on_edit_start {
    Some(f) => f()
    None => ()
  }

  // Start inplace input
  @io.start_inplace_input(
    row,
    col,
    width,
    height,
    multiline,
    current_value,
    fn(result) {
      match result {
        @io.InputResult::Confirmed(new_value) => (config.on_change)(new_value)
        @io.InputResult::Cancelled => ()
        @io.InputResult::ForceQuit => {
          // Call force quit handler if provided
          match config.on_force_quit {
            Some(f) => f()
            None => ()
          }
          // Don't call on_complete - we're quitting
          return
        }
        _ => ()
      }

      // Call optional cleanup callback
      match config.on_edit_end {
        Some(f) => f()
        None => ()
      }
      on_complete()
    },
    confirm_on_shift_enter~,
    esc_cancels~,
    on_lines_change~,
    on_completion~,
  )
}

///|
/// Start editing within bounds (HitTestResult) with border adjustment.
/// bounds.x/y are 0-indexed; row/col for ANSI are 1-indexed.

///|
/// Helper to create a standard edit config for form fields
pub fn form_edit_config(
  field_name : String,
  signal : @signals.Signal[String],
  on_edit_start? : (() -> Unit)? = None,
  on_edit_end? : (() -> Unit)? = None,
  on_force_quit? : (() -> Unit)? = None,
) -> EditConfig {
  {
    field_name,
    on_change: fn(value) { signal.set(value) },
    on_edit_start,
    on_edit_end,
    on_force_quit,
  }
}

///|
/// Context for managing multiple editable fields
pub(all) struct EditContext {
  /// Currently focused field ID
  focused_id : @signals.Signal[String]
  /// Map of field ID to edit config
  configs : Map[String, EditConfig]
  /// Called to restore TUI mode after editing
  restore_tui : () -> Unit
}

///|
/// Create a new edit context
pub fn EditContext::new(
  focused_id : @signals.Signal[String],
  restore_tui : () -> Unit,
) -> EditContext {
  { focused_id, configs: {}, restore_tui }
}

///|
/// Register a field with the context
pub fn EditContext::register(
  self : EditContext,
  id : String,
  config : EditConfig,
) -> Unit {
  self.configs[id] = config
}

///|
/// Start editing the currently focused field
pub fn EditContext::edit_focused(self : EditContext) -> Bool {
  let id = self.focused_id.get()
  match self.configs.get(id) {
    Some(config) => {
      // Get current value from signal if available
      let current_value = ""
      start_edit(config, current_value, fn() { (self.restore_tui)() })
      true
    }
    None => false
  }
}

///|
/// Start editing a specific field by ID
pub fn EditContext::edit(
  self : EditContext,
  id : String,
  current_value : String,
) -> Bool {
  match self.configs.get(id) {
    Some(config) => {
      start_edit(config, current_value, fn() { (self.restore_tui)() })
      true
    }
    None => false
  }
}