import { ClickEvent, TouchStartEvent, LongPressEvent } from "../runtime/touch"
import type { ClickEvent as ClickEventType, TouchStartEvent as TouchStartEventType, LongPressEvent as LongPressEventType } from "../runtime/touch"
import { type ElementStyle, type ContainerStyle, ContainerElement, buildUI, type DrawableStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn, type BaseStyle, type Color } from "./UINode"

export type UIButtonStyle = ElementStyle & DrawableStyle & ContainerStyle & { rippleColor?: Color | "default" }

/** A tappable container — row + centered children by default. Press feedback via the `onPressed`
 *  style block, the `$pressed` class, or `rippleColor`. */
export interface UIButton extends UIContainerBase<UIButtonStyle & { onPressed?: UIButtonStyle & { duration?: number } }, DrawableStyle & BaseStyle> {
  readonly type: "button",

  /** Fired on a completed tap/click. */
  onClick(callback: (ev: ClickEventType<UIButton>) => void): this,
  /** Fired when a touch begins; `ev.track(...)` takes over the rest of the gesture (dragging). */
  onTouchStart(callback: (ev: TouchStartEventType<UIButton>) => void): this,
  /** Fired when a finger is held on the button past the long-press threshold. The event can
   *  `ev.track(...)` the rest of the gesture (like `onTouchStart`), so a hold can flow straight into
   *  dragging the element. A handled long-press suppresses the click that would follow the release. */
  onLongPress(callback: (ev: LongPressEventType<UIButton>) => void): this,
  /** Is a finger currently down on the button? */
  isPressed(): boolean,
}


class ButtonElement extends ContainerElement<"button"> {

  readonly clickListeners: any[] = []
  readonly touchStartListeners: any[] = []
  readonly longPressListeners: any[] = []

  onClick (callback: any): this {
    this.clickListeners.push(callback)
    return this
  }
  _emitClick(pointerId: number, clientX: number, clientY: number) {
    const touchEvent = new ClickEvent(clientX, clientY, pointerId)
    touchEvent.target = this
    for (let callback of this.clickListeners) {
      callback(touchEvent)
    }
    return null
  }

  onTouchStart (callback: any): this {
    this.touchStartListeners.push(callback)
    return this
  }
  _emitTouchStart(pointerId: number, clientX: number, clientY: number): any {
    const touchEvent = new TouchStartEvent(clientX, clientY, pointerId)
    touchEvent.target = this
    for (let callback of this.touchStartListeners) {
      callback(touchEvent)
      if ((touchEvent as any)._trackHandler) {
        return (touchEvent as any)._trackHandler
      }
    }
    return null
  }

  onLongPress (callback: any): this {
    this.longPressListeners.push(callback)
    return this
  }
  // Fired by the host when the finger is held past the long-press threshold. Returns null when
  // nothing is listening — the host then lets the trailing click through as usual. Otherwise it
  // returns an object whose presence tells the host to swallow that click, carrying the optional
  // drag handler a listener registered via `ev.track(...)` for the host to drive the gesture.
  _emitLongPress(pointerId: number, clientX: number, clientY: number): any {
    if (this.longPressListeners.length === 0) return null
    const longPressEvent = new LongPressEvent(clientX, clientY, pointerId)
    longPressEvent.target = this
    for (let callback of this.longPressListeners) {
      callback(longPressEvent)
    }
    return { track: (longPressEvent as any)._trackHandler ?? null }
  }

  isPressed(): boolean {
    if (!this._id) return false
    return _creatorUI.isButtonPressed(this._id)
  }
}

// Buttons are row + centered by default: the icon+label button is the norm, and yoga's column
// default was a recurring authoring/codegen trap.
const BUTTON_DEFAULTS = { flexDirection: "row", justifyContent: "center", alignItems: "center" } as const

const makeButton = (style: any, children: any) => new ButtonElement("button", style, children)

/** @internal Compiler fast path (chisel `flatten_ui` raw lowering) — see UIContainer. */
export const __UIButton = (children: UINodeChild[] | ChildrenFn): UIButton => makeButton({ ...BUTTON_DEFAULTS }, children)

/** Create a button (row + centered by default — the icon+label shape). Same argument forms as
 *  `UIColumn`; attach behavior with `.onClick(...)`. */
export function UIButton(...children: UIChildArg[]): UIButton;
export function UIButton(children: UINodeChild[] | ChildrenFn): UIButton;
/** @deprecated Style as the first argument is legacy — use chained `.style({...})`. */
export function UIButton(style: UIButtonStyle, children?: UINodeChild[] | ChildrenFn): UIButton;
export function UIButton(...args: any[]): UIButton {
  return buildUI(args, BUTTON_DEFAULTS, makeButton)
}
