import { TouchStartEvent } from "../runtime/touch"
import { _bumpNavEpoch, _navSupported, _setCurrent, Presentable, type PresentOptions } from "./presentable"
import { ContainerElement, buildUI, type BaseStyle, type ContainerStyle, type DrawableStyle, type PaddingStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn, } from "./UINode"

export type UIScreenStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle

/** A screen — the root the router/host mounts, sized to its slot. A screen NEVER scrolls: it is
 *  fixed chrome (header, tab bar) plus, when the content overflows, one `UIScrollable` body child
 *  (`flexGrow: 1`). Scroll events and pull-to-refresh live on the scroll containers
 *  (`UIScrollable`, `UIVirtualizedList`). */
export interface UIScreen extends UIContainerBase<UIScreenStyle, DrawableStyle & BaseStyle> {
  readonly type: "screen",

  /** Show this screen as the current destination (replaces whatever is visible — a screen, a
   *  scene, a native view — suspending an active Router until `Router.restore()`). */
  open(options?: PresentOptions): void,
  /** Dismiss if this screen is the visible destination. */
  close(): void

  /** Hardware/system back while this screen is current. */
  onBackPressed(callback: () => void): this

  /** The screen became the visible destination (first open, or revealed by a pop). */
  onOpen(callback: () => void): this
  /** The screen stopped being visible — closed, replaced, or covered by a push. */
  onClose(callback: () => void): this

  /**
   * Keep this screen's built native tree alive when a host detaches it: instead of being destroyed,
   * its views + layout + live state (scroll position, input text) are retained, so re-hosting the
   * SAME screen object restores it in place rather than rebuilding. `onClose`/`onOpen` still fire on
   * detach/re-attach. You own the lifetime — a kept tree is freed only by `dispose()` or when the
   * project unloads. (Native-only today; web rebuilds.)
   */
  keepAlive(enabled?: boolean): this
  /** Free a `keepAlive()` screen's retained tree now. No-op unless it's currently detached-and-kept. */
  dispose(): this

  /** Touch began on the screen; `ev.track(...)` takes over the rest of the gesture. */
  onTouchStart(callback: (ev: TouchStartEvent<UIScreen>) => void): this,
}

export class ScreenElement extends ContainerElement<"screen"> {
  open(options?: PresentOptions): void {
    _bumpNavEpoch()
    if (_navSupported()) {
      _creatorUI.openView!(this, options?.transition ?? "none")
    } else {
      // Legacy host: no destination navigation — transition is dropped.
      _creatorUI.openScreen(this)
    }
    _setCurrent(this as any)
  }
  close(): void {
    _bumpNavEpoch()
    if (_navSupported()) {
      _creatorUI.closeView!()
    } else {
      _creatorUI.closeScreen()
    }
    if (Presentable.current === (this as any)) _setCurrent(null)
  }
  protected ol: (() => void)[] = []
  onOpen(callback: () => void): this {
    this.ol.push(callback)
    return this
  }
  protected cl: (() => void)[] = []
  onClose(callback: () => void): this {
    this.cl.push(callback)
    return this
  }
  // Read by the host at detach time (a plain flag on the node, like _interactive).
  _keepAlive = false
  keepAlive(enabled = true): this {
    this._keepAlive = enabled
    return this
  }
  dispose(): this {
    // Rides the generic command channel (no dedicated bridge). No-op while _id is 0 (never mounted)
    // or when the tree isn't currently detached-and-kept — the host ignores it then.
    if (this._id !== 0) _creatorUI.command(this, "disposeKeepAlive")
    return this
  }
  readonly touchStartListeners: any[] = []
  _interactive = false
  onTouchStart (callback: any): this {
    this._interactive = true
    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
  }
  _backButtonCallback?: () => void
  onBackPressed(callback: any): this {
    this._backButtonCallback = callback
    return this
  }
}

const makeScreen = (style: any, children: any) => new ScreenElement("screen", style, children)

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

/** Create a screen. Present it with `.open()`, or via `Router` / `UIPager`. Same argument forms
 *  as `UIColumn`. */
export function UIScreen(...children: UIChildArg[]): UIScreen;
export function UIScreen(children: UINodeChild[] | ChildrenFn): UIScreen;
/** @deprecated Style as the first argument is legacy — use chained `.style({...})`. */
export function UIScreen(style: UIScreenStyle, children?: UINodeChild[] | ChildrenFn): UIScreen;
export function UIScreen(...args: any[]): UIScreen {
  return buildUI(args, null, makeScreen)
}
