///|
/// Message-independent behavior for a low-level custom view node.
///
/// The trait is open so downstream packages can define renderer-neutral
/// controls. Typed children and messages are attached with `View::from_node`.
/// `identity` controls element reuse: equal identities preserve transient
/// runtime control state, while a changed kind or key remounts the element.
/// `declaration` classifies immutable declaration data independently for
/// layout, paint, semantics, and platform work. Its conservative default marks
/// every channel uncacheable; performance-sensitive nodes opt into exact or
/// constant channels explicitly. Application state belongs in the TEA model
/// and transient interaction state belongs in runtime-owned element state
/// exposed through the typed adapters.
pub(open) trait ViewNode {
  fn identity(Self) -> ViewIdentity
  fn declaration(Self) -> ViewDeclaration = _
  fn child_constraints(Self, Constraints) -> Constraints = _
  fn child_environment(Self, Environment) -> Environment = _
  fn child_style(Self, ViewStyle) -> ViewStyle = _
  fn layout(Self, ViewLayoutContext) -> ViewLayoutResult
  fn paint(Self, ViewPaintContext) -> ViewPaintPlan = _
  fn platform_views(Self, ViewPlatformContext) -> Array[PlatformViewPlacement] = _
  fn text_input_state(Self, ViewPaintContext) -> TextInputState? = _
  fn semantics(Self) -> ViewSemanticsInfo = _
  fn focusable(Self) -> Bool = _
  fn focus_trap(Self) -> Bool = _
  fn flex_weight(Self) -> Double = _
}

// Future: when MoonBit supports blanket trait impls, decompose ViewNode into
// finer-grained traits: LayoutNode (identity, declaration, child_constraints,
// child_environment, child_style, layout, flex_weight), PaintNode (paint),
// SemanticsViewNode (semantics), FocusNode (focusable). This lets new controls
// implement only what they need. For now, all 14 methods live on ViewNode.

///|
impl ViewNode with fn declaration(_self) {
  ViewDeclaration::uncacheable()
}

///|
impl ViewNode with fn child_constraints(_self, constraints) {
  constraints.loosen()
}

///|
impl ViewNode with fn child_environment(_self, environment) {
  environment
}

///|
impl ViewNode with fn child_style(_self, style) {
  style
}

///|
impl ViewNode with fn paint(_self, _context) {
  ViewPaintPlan::empty()
}

///|
impl ViewNode with fn platform_views(_self, _context) {
  []
}

///|
impl ViewNode with fn text_input_state(_self, _context) {
  None
}

///|
impl ViewNode with fn semantics(_self) {
  ViewSemanticsInfo::new()
}

///|
impl ViewNode with fn focusable(_self) {
  false
}

///|
impl ViewNode with fn focus_trap(_self) {
  false
}

///|
impl ViewNode with fn flex_weight(_self) {
  0.0
}

///|
priv struct EmptyViewNode {}

///|
impl ViewNode for EmptyViewNode with fn identity(_self) {
  ViewIdentity::new(kind="Empty")
}

///|
impl ViewNode for EmptyViewNode with fn declaration(_self) {
  ViewDeclaration::constant()
}

///|
impl ViewNode for EmptyViewNode with fn layout(_self, context) {
  ViewLayoutResult::new(
    size=context.constraints.constrain(Size::new(width=0.0, height=0.0)),
  )
}

///|
fn[Msg] empty_view() -> View[Msg] {
  View::from_node(EmptyViewNode::{  })
}

///|
priv struct ViewAdapter[Msg] {
  node : &ViewNode
  identity_snapshot : ViewIdentity
  declaration_snapshot : ViewDeclaration
  semantics_snapshot : ViewSemanticsInfo
  focusable_snapshot : Bool
  focus_trap_snapshot : Bool
  semantics_action_handlers : Array[ViewSemanticsActionHandler[Msg]]
  children_snapshot : Array[View[Msg]]
  event_fn : (ViewEventContext) -> ViewEventResult[Msg]
  text_command_fn : (ViewEventContext, CommandIntent, String?) -> ViewTextCommandResult[
    Msg,
  ]
}

///|
fn[Msg] ViewAdapter::new(
  node~ : &ViewNode,
  identity~ : ViewIdentity,
  declaration~ : ViewDeclaration,
  semantics~ : ViewSemanticsInfo,
  focusable~ : Bool,
  focus_trap~ : Bool,
  semantics_action_handlers~ : Array[ViewSemanticsActionHandler[Msg]],
  children~ : Array[View[Msg]],
  event~ : (ViewEventContext) -> ViewEventResult[Msg],
  text_command~ : (ViewEventContext, CommandIntent, String?) -> ViewTextCommandResult[
    Msg,
  ],
) -> ViewAdapter[Msg] {
  {
    node,
    identity_snapshot: identity,
    declaration_snapshot: declaration,
    semantics_snapshot: semantics,
    focusable_snapshot: focusable,
    focus_trap_snapshot: focus_trap,
    semantics_action_handlers: semantics_action_handlers.copy(),
    children_snapshot: children.copy(),
    event_fn: event,
    text_command_fn: text_command,
  }
}

///|
fn[Msg] ViewAdapter::children(self : ViewAdapter[Msg]) -> Array[View[Msg]] {
  self.children_snapshot.copy()
}

///|
fn[Msg] ViewAdapter::event(
  self : ViewAdapter[Msg],
  context : ViewEventContext,
) -> ViewEventResult[Msg] {
  (self.event_fn)(context)
}

///|
fn[Msg] ViewAdapter::text_command_result(
  self : ViewAdapter[Msg],
  context : ViewEventContext,
  intent : CommandIntent,
  paste_text? : String? = None,
) -> ViewTextCommandResult[Msg] {
  (self.text_command_fn)(context, intent, paste_text)
}

///|
fn[Msg, NextMsg] ViewAdapter::map(
  self : ViewAdapter[Msg],
  map : (Msg) -> NextMsg,
) -> ViewAdapter[NextMsg] {
  ViewAdapter::new(
    node=self.node,
    identity=self.identity_snapshot,
    declaration=self.declaration_snapshot,
    semantics=self.semantics_snapshot,
    focusable=self.focusable_snapshot,
    focus_trap=self.focus_trap_snapshot,
    semantics_action_handlers=self.semantics_action_handlers.map(handler => {
      handler.map(map)
    }),
    children=self.children_snapshot.map(child => child.map(map)),
    event=context => {
      let result = self.event(context)
      {
        changed: result.changed,
        activated: result.activated,
        focused: result.focused,
        captured: result.captured,
        state: result.state,
        text_control: result.text_control,
        dirty: result.dirty,
        messages: result.messages.map(message => map(message)),
      }
    },
    text_command=(context, intent, paste_text) => {
      let result = self.text_command_result(context, intent, paste_text~)
      {
        result: result.result,
        text_control: result.text_control,
        messages: result.messages.map(message => map(message)),
      }
    },
  )
}

///|
fn[Msg] ViewAdapter::semantics_action_kinds(
  self : ViewAdapter[Msg],
) -> Array[SemanticsActionKind] {
  let kinds : Array[SemanticsActionKind] = []
  if self.focusable_snapshot {
    kinds.push(SemanticsActionKind::Focus)
  }
  for handler in self.semantics_action_handlers {
    if !kinds.contains(handler.kind()) {
      kinds.push(handler.kind())
    }
  }
  kinds
}

///|
fn[Msg] ViewAdapter::dispatch_semantics_action(
  self : ViewAdapter[Msg],
  context : ViewSemanticsActionContext,
  action : SemanticsAction,
) -> ViewSemanticsActionResult[Msg] {
  let kind = action.kind()
  for handler in self.semantics_action_handlers {
    if handler.kind() == kind {
      return handler.dispatch(context, action)
    }
  }
  ViewSemanticsActionResult::rejected()
}