///|
const InputBaseStyle : String = "display:block;width:100%;height:32px;margin:0;padding:4px 12px;border:1px solid var(--sumi-stroke,rgba(204,221,255,0.1));border-radius:var(--sumi-radius,8px);background:var(--sumi-block,rgba(255,255,255,0.08));font-size:13px;line-height:22px;color:var(--sumi-text,#ffffff);outline:none;appearance:none;-webkit-appearance:none"

///|
const InputErrorStyle : String = "border-color:var(--sumi-error,#ff3355)"

///|
const InputAdornmentStyle : String = "position:absolute;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;color:var(--sumi-text-placeholder,rgba(255,255,255,0.35));pointer-events:none"

///|
/// A single-line text field. Controlled: the caller owns the value.
///
/// `prefix`/`suffix` slot icons or text inside the field; `clearable=true`
/// shows a small ✕ while the value is non-empty (clears through `on_input`
/// or the explicit `on_clear`). `error`/`error_text` render the design's
/// error border and an optional hint line below the field.
pub fn input(
  value~ : String,
  placeholder? : String = "",
  input_type? : @html.InputType = Text,
  on_input? : @internal.Emit[String],
  on_change? : @internal.Emit[String],
  on_clear? : @cmd.Cmd,
  clearable? : Bool = false,
  prefix? : @html.Html,
  suffix? : @html.Html,
  error? : Bool = false,
  error_text? : String,
  disabled? : Bool = false,
  read_only? : Bool = false,
  name? : String,
  maxlength? : Int,
  autofocus? : Bool,
  id? : String,
  class? : String,
  title? : String,
  attrs? : @html.Attrs,
  style? : Array[String] = [],
) -> @html.Html {
  let element_attrs = @internal.sumi_attrs(attrs).data_set("slot", "input")
  if disabled {
    ignore(element_attrs.disabled(true))
  }
  if error {
    ignore(element_attrs.aria_invalid("true"))
  }
  let has_prefix = prefix is Some(_)
  let trailing_count = (if suffix is Some(_) { 1 } else { 0 }) +
    (if clearable && !value.is_empty() { 1 } else { 0 })
  let padding = (if has_prefix { "padding-left:32px;" } else { "" }) +
    (match trailing_count {
      0 => ""
      1 => "padding-right:32px;"
      _ => "padding-right:52px;"
    })
  let field = @html.input(
    input_type~,
    value~,
    placeholder~,
    on_input?,
    on_change?,
    read_only~,
    name?,
    maxlength?,
    autofocus?,
    id?,
    class?,
    title?,
    style=[
      @internal.SumiBoxSizing,
      @internal.SumiFontSans,
      @internal.SumiTextRendering,
      @internal.SumiTransition,
      InputBaseStyle,
      padding,
      if error {
        InputErrorStyle
      } else {
        ""
      },
      if disabled {
        @internal.SumiDisabled +
        ";color:var(--sumi-text-disabled,rgba(255,255,255,0.2))"
      } else {
        ""
      },
    ],
    attrs=element_attrs,
  )
  let prefix_view : @html.Html = match prefix {
    Some(content) =>
      @html.span(
        style=[InputAdornmentStyle, "left:10px"],
        attrs=@html.Attrs::build().data_set("slot", "input-prefix"),
        [content],
      )
    None => @html.nothing
  }
  let suffix_view : @html.Html = match suffix {
    Some(content) =>
      @html.span(
        style=[InputAdornmentStyle, "right:10px"],
        attrs=@html.Attrs::build().data_set("slot", "input-suffix"),
        [content],
      )
    None => @html.nothing
  }
  let clear_view : @html.Html = if clearable && !value.is_empty() && !disabled {
    let clear_cmd : @cmd.Cmd? = match on_clear {
      Some(cmd) => Some(cmd)
      None => on_input.map(emit => emit(""))
    }
    @html.button(
      style=[
        @internal.SumiBoxSizing,
        @internal.SumiTransition,
        "position:absolute;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0;padding:0;border:none;background:transparent;color:var(--sumi-text-placeholder,rgba(255,255,255,0.35));cursor:pointer;appearance:none;-webkit-appearance:none;outline:none",
        if suffix is Some(_) {
          "right:32px"
        } else {
          "right:8px"
        },
      ],
      type_="button",
      on_click?=clear_cmd,
      attrs=@html.Attrs::build()
        .data_set("slot", "input-clear")
        .aria_label("Clear"),
      [@primitives.icon_x(size=12)],
    )
  } else {
    @html.nothing
  }
  let error_view : @html.Html = match error_text {
    Some(text) if error =>
      @html.div(
        style=[
          @internal.SumiFontSans,
          "margin-top:6px;font-size:12px;line-height:20px;color:var(--sumi-error,#ff3355)",
        ],
        attrs=@html.Attrs::build().data_set("slot", "input-error"),
        text,
      )
    _ => @html.nothing
  }
  @html.div(
    style=@internal.sumi_styles(
      [@internal.SumiBoxSizing, "position:relative;display:block;width:100%"],
      style,
    ),
    attrs=@html.Attrs::build().data_set("slot", "input-root"),
    [
      @html.div(
        style=["position:relative;display:flex;align-items:center;width:100%"],
        [field, prefix_view, suffix_view, clear_view],
      ),
      error_view,
    ],
  )
}