///|
/// Platform layer contracts (window/event/input).
/// Ebiten refs:
/// - internal/ui/ui.go
/// - internal/ui/ui_glfw.go
/// - internal/ui/input_*.go
/// - internal/inputstate/inputstate.go

///|
pub struct WindowOptions {
  title : String
  width : Int
  height : Int
  transparent : Bool
  resizable : Bool
  focused : Bool
} derive(Debug)

///|
pub impl Show for WindowOptions with fn output(self, logger) {
  logger.write_object(Repr(self))
}

///|
pub struct MonitorInfo {
  width : Int
  height : Int
  device_scale_factor : Double
  refresh_rate_hz : Int
} derive(Debug)

///|
pub impl Show for MonitorInfo with fn output(self, logger) {
  logger.write_object(Repr(self))
}

///|
pub enum FullscreenMode {
  Windowed
  Borderless
  Exclusive
} derive(Debug)

///|
pub impl Show for FullscreenMode with fn output(self, logger) {
  logger.write_object(Repr(self))
}

///|
pub fn fullscreen_mode_to_int(mode : FullscreenMode) -> Int {
  match mode {
    FullscreenMode::Windowed => 0
    FullscreenMode::Borderless => 1
    FullscreenMode::Exclusive => 2
  }
}

///|
pub fn fullscreen_mode_from_int(mode : Int) -> FullscreenMode {
  match mode {
    1 => FullscreenMode::Borderless
    2 => FullscreenMode::Exclusive
    _ => FullscreenMode::Windowed
  }
}

///|
pub enum CursorMode {
  Visible
  Hidden
  Captured
} derive(Debug)

///|
pub impl Show for CursorMode with fn output(self, logger) {
  logger.write_object(Repr(self))
}

///|
pub fn cursor_mode_to_int(mode : CursorMode) -> Int {
  match mode {
    CursorMode::Visible => 0
    CursorMode::Hidden => 1
    CursorMode::Captured => 2
  }
}

///|
pub fn cursor_mode_from_int(mode : Int) -> CursorMode {
  match mode {
    1 => CursorMode::Hidden
    2 => CursorMode::Captured
    _ => CursorMode::Visible
  }
}

///|
pub enum AsyncRequestStatus {
  Idle
  Pending
  Confirmed
  Rejected
} derive(Debug)

///|
pub impl Show for AsyncRequestStatus with fn output(self, logger) {
  logger.write_object(Repr(self))
}

///|
pub fn async_request_status_to_int(status : AsyncRequestStatus) -> Int {
  match status {
    AsyncRequestStatus::Idle => 0
    AsyncRequestStatus::Pending => 1
    AsyncRequestStatus::Confirmed => 2
    AsyncRequestStatus::Rejected => 3
  }
}

///|
pub fn async_request_status_from_int(status : Int) -> AsyncRequestStatus {
  match status {
    1 => AsyncRequestStatus::Pending
    2 => AsyncRequestStatus::Confirmed
    3 => AsyncRequestStatus::Rejected
    _ => AsyncRequestStatus::Idle
  }
}

///|
pub fn new_window_options(
  title : String,
  width : Int,
  height : Int,
  transparent : Bool,
  resizable : Bool,
  focused? : Bool = true,
) -> WindowOptions {
  { title, width, height, transparent, resizable, focused, }
}

///|
pub(open) trait PlatformDriver {
  /// Ebiten ref: UserInterface.init / Run
  fn initialize(Self, options : WindowOptions) -> Unit raise

  /// Ebiten ref: ui.loopGame event pump
  fn poll_events(Self) -> Unit

  /// Ebiten ref: window close handling in ui/inputstate
  fn should_close(Self) -> Bool

  /// Ebiten ref: Game.Layout outside size inputs
  fn outside_size(Self) -> @core.OutsideSize

  /// Ebiten ref: inputstate snapshot per tick
  fn capture_input(Self, tick : Int) -> @core.InputSnapshot

  /// Ebiten ref: device scale factor paths in ui/context
  fn monitor_info(Self) -> MonitorInfo

  /// Ebiten ref: SetFullscreen/IsFullscreen
  fn set_fullscreen(Self, enabled : Bool) -> Unit
  fn is_fullscreen(Self) -> Bool

  /// Ebiten ref: SetCursorMode/CursorMode
  fn set_cursor_mode(Self, mode : CursorMode) -> Unit
  fn cursor_mode(Self) -> CursorMode

  /// Ebiten ref: DeviceScaleFactor
  fn set_device_scale_factor(Self, scale : Double) -> Unit
  fn device_scale_factor(Self) -> Double

  /// Ebiten ref: SetVsyncEnabled/IsVsyncEnabled
  fn set_vsync_enabled(Self, enabled : Bool) -> Unit
  fn is_vsync_enabled(Self) -> Bool

  /// Ebiten ref: window close/requestAttention
  fn close_window(Self) -> Unit
  fn request_attention(Self) -> Unit

  /// Mouse-to-touch fallback (opt-in, default false)
  fn set_mouse_touch_fallback(Self, enabled : Bool) -> Unit
  fn mouse_touch_fallback_enabled(Self) -> Bool

  /// Async request status for fullscreen and cursor mode
  fn fullscreen_request_status(Self) -> AsyncRequestStatus
  fn cursor_mode_request_status(Self) -> AsyncRequestStatus
}

///|
pub struct DesktopGlfwPlatform {
  mut initialized : Bool
  mut poll_count : Int
  close_after_polls : Int
  mut native_active : Bool
  mut options : WindowOptions
  mut current_input : @core.InputSnapshot
  mut fullscreen : Bool
  mut cursor_mode : CursorMode
  mut device_scale_factor : Double
  mut vsync_enabled : Bool
  mut close_requested : Bool
  mut attention_requests : Int
  mut mouse_touch_fallback : Bool
  mut fullscreen_request_status : AsyncRequestStatus
  mut cursor_mode_request_status : AsyncRequestStatus
}

///|
pub struct WebCanvasPlatform {
  canvas_selector : String
  mut initialized : Bool
  mut poll_count : Int
  close_after_polls : Int
  mut web_active : Bool
  mut options : WindowOptions
  mut current_input : @core.InputSnapshot
  mut fullscreen : Bool
  mut cursor_mode : CursorMode
  mut device_scale_factor : Double
  mut vsync_enabled : Bool
  mut close_requested : Bool
  mut attention_requests : Int
  mut mouse_touch_fallback : Bool
  mut fullscreen_request_status : AsyncRequestStatus
  mut cursor_mode_request_status : AsyncRequestStatus
}

///|
pub fn create_desktop_glfw_platform() -> DesktopGlfwPlatform {
  {
    initialized: false,
    poll_count: 0,
    close_after_polls: 2,
    native_active: false,
    options: {
      title: "kagura",
      width: 800,
      height: 600,
      transparent: false,
      resizable: true,
      focused: true,
    },
    current_input: @core.empty_input_snapshot(),
    fullscreen: false,
    cursor_mode: CursorMode::Visible,
    device_scale_factor: 1.0,
    vsync_enabled: true,
    close_requested: false,
    attention_requests: 0,
    mouse_touch_fallback: false,
    fullscreen_request_status: AsyncRequestStatus::Idle,
    cursor_mode_request_status: AsyncRequestStatus::Idle,
  }
}

///|
pub fn create_web_canvas_platform(
  canvas_selector : String,
) -> WebCanvasPlatform {
  {
    canvas_selector,
    initialized: false,
    poll_count: 0,
    close_after_polls: 2,
    web_active: false,
    options: {
      title: "kagura-web",
      width: 800,
      height: 600,
      transparent: true,
      resizable: true,
      focused: true,
    },
    current_input: @core.empty_input_snapshot(),
    fullscreen: false,
    cursor_mode: CursorMode::Visible,
    device_scale_factor: 1.0,
    vsync_enabled: true,
    close_requested: false,
    attention_requests: 0,
    mouse_touch_fallback: false,
    fullscreen_request_status: AsyncRequestStatus::Idle,
    cursor_mode_request_status: AsyncRequestStatus::Idle,
  }
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn initialize(
  self,
  options,
) {
  self.options = options
  self.native_active = desktop_try_native_initialize(options)
  self.initialized = true
  self.poll_count = 0
  self.close_requested = false
  self.attention_requests = 0
  self.fullscreen = desktop_native_is_fullscreen(
    self.native_active,
    self.fullscreen,
  )
  self.cursor_mode = desktop_native_cursor_mode(
    self.native_active,
    self.cursor_mode,
  )
  self.device_scale_factor = desktop_native_device_scale_factor(
    self.native_active,
    self.device_scale_factor,
  )
  self.vsync_enabled = desktop_native_is_vsync_enabled(
    self.native_active,
    self.vsync_enabled,
  )
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn poll_events(self) {
  if self.initialized {
    desktop_poll_native(self.native_active)
    self.poll_count = self.poll_count + 1
  }
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn should_close(self) {
  if self.close_requested {
    true
  } else if self.native_active {
    self.initialized && desktop_native_should_close()
  } else {
    self.initialized && self.poll_count >= self.close_after_polls
  }
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn outside_size(self) {
  if self.native_active {
    desktop_native_outside_size(self.options.width, self.options.height)
  } else {
    @core.new_outside_size(
      self.options.width.to_double(),
      self.options.height.to_double(),
    )
  }
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn capture_input(
  self,
  tick,
) {
  self.current_input = desktop_native_capture_input(self.native_active, tick)
  self.current_input
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn monitor_info(self) {
  let outside = self.outside_size()
  self.device_scale_factor = desktop_native_device_scale_factor(
    self.native_active,
    self.device_scale_factor,
  )
  if self.device_scale_factor <= 0.0 {
    self.device_scale_factor = 1.0
  }
  {
    width: outside.width.to_int(),
    height: outside.height.to_int(),
    device_scale_factor: self.device_scale_factor,
    refresh_rate_hz: 60,
  }
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn set_fullscreen(
  self,
  enabled,
) {
  self.fullscreen = desktop_native_set_fullscreen(self.native_active, enabled)
  self.fullscreen_request_status = AsyncRequestStatus::Confirmed
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn is_fullscreen(self) {
  self.fullscreen = desktop_native_is_fullscreen(
    self.native_active,
    self.fullscreen,
  )
  self.fullscreen
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn set_cursor_mode(
  self,
  mode,
) {
  self.cursor_mode = desktop_native_set_cursor_mode(self.native_active, mode)
  self.cursor_mode_request_status = AsyncRequestStatus::Confirmed
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn cursor_mode(self) {
  self.cursor_mode = desktop_native_cursor_mode(
    self.native_active,
    self.cursor_mode,
  )
  self.cursor_mode
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn set_device_scale_factor(
  self,
  scale,
) {
  let requested_scale = if scale <= 0.0 { 1.0 } else { scale }
  self.device_scale_factor = desktop_native_set_device_scale_factor(
    self.native_active,
    requested_scale,
  )
  if self.device_scale_factor <= 0.0 {
    self.device_scale_factor = 1.0
  }
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn device_scale_factor(
  self,
) {
  self.device_scale_factor = desktop_native_device_scale_factor(
    self.native_active,
    self.device_scale_factor,
  )
  if self.device_scale_factor <= 0.0 {
    self.device_scale_factor = 1.0
  }
  self.device_scale_factor
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn set_vsync_enabled(
  self,
  enabled,
) {
  self.vsync_enabled = desktop_native_set_vsync_enabled(
    self.native_active,
    enabled,
  )
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn is_vsync_enabled(self) {
  self.vsync_enabled = desktop_native_is_vsync_enabled(
    self.native_active,
    self.vsync_enabled,
  )
  self.vsync_enabled
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn close_window(self) {
  self.close_requested = true
  desktop_native_close_window(self.native_active)
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn request_attention(self) {
  self.attention_requests = self.attention_requests + 1
  desktop_native_request_attention(self.native_active)
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn set_mouse_touch_fallback(
  self,
  enabled,
) {
  self.mouse_touch_fallback = enabled
  desktop_native_set_mouse_touch_fallback(self.native_active, enabled)
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn mouse_touch_fallback_enabled(
  self,
) {
  self.mouse_touch_fallback
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn fullscreen_request_status(
  self,
) {
  self.fullscreen_request_status
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with fn cursor_mode_request_status(
  self,
) {
  self.cursor_mode_request_status
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn initialize(self, options) {
  self.options = options
  self.web_active = web_try_initialize(self.canvas_selector, options)
  self.initialized = true
  self.poll_count = 0
  self.close_requested = false
  self.attention_requests = 0
  self.fullscreen = web_is_fullscreen(
    self.canvas_selector,
    self.web_active,
    self.fullscreen,
  )
  self.cursor_mode = web_cursor_mode(
    self.canvas_selector,
    self.web_active,
    self.cursor_mode,
  )
  self.device_scale_factor = web_device_scale_factor(
    self.canvas_selector,
    self.web_active,
    self.device_scale_factor,
  )
  self.vsync_enabled = web_is_vsync_enabled(
    self.canvas_selector,
    self.web_active,
    self.vsync_enabled,
  )
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn poll_events(self) {
  if self.initialized {
    web_poll(self.web_active)
    self.poll_count = self.poll_count + 1
  }
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn should_close(self) {
  if self.close_requested {
    true
  } else if self.web_active {
    self.initialized && web_should_close()
  } else {
    self.initialized && self.poll_count >= self.close_after_polls
  }
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn outside_size(self) {
  if self.web_active {
    web_outside_size(self.options.width, self.options.height)
  } else {
    @core.new_outside_size(
      self.options.width.to_double(),
      self.options.height.to_double(),
    )
  }
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn capture_input(self, tick) {
  self.current_input = web_capture_input(self.web_active, tick)
  self.current_input
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn monitor_info(self) {
  self.device_scale_factor = web_device_scale_factor(
    self.canvas_selector,
    self.web_active,
    self.device_scale_factor,
  )
  if self.device_scale_factor <= 0.0 {
    self.device_scale_factor = 1.0
  }
  {
    width: self.options.width,
    height: self.options.height,
    device_scale_factor: self.device_scale_factor,
    refresh_rate_hz: 60,
  }
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn set_fullscreen(
  self,
  enabled,
) {
  self.fullscreen_request_status = AsyncRequestStatus::Pending
  self.fullscreen = web_set_fullscreen(
    self.canvas_selector,
    self.web_active,
    enabled,
  )
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn is_fullscreen(self) {
  self.fullscreen = web_is_fullscreen(
    self.canvas_selector,
    self.web_active,
    self.fullscreen,
  )
  self.fullscreen
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn set_cursor_mode(
  self,
  mode,
) {
  self.cursor_mode_request_status = AsyncRequestStatus::Pending
  self.cursor_mode = web_set_cursor_mode(
    self.canvas_selector,
    self.web_active,
    mode,
  )
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn cursor_mode(self) {
  self.cursor_mode = web_cursor_mode(
    self.canvas_selector,
    self.web_active,
    self.cursor_mode,
  )
  self.cursor_mode
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn set_device_scale_factor(
  self,
  scale,
) {
  let requested_scale = if scale <= 0.0 { 1.0 } else { scale }
  self.device_scale_factor = web_set_device_scale_factor(
    self.canvas_selector,
    self.web_active,
    requested_scale,
  )
  if self.device_scale_factor <= 0.0 {
    self.device_scale_factor = 1.0
  }
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn device_scale_factor(self) {
  self.device_scale_factor = web_device_scale_factor(
    self.canvas_selector,
    self.web_active,
    self.device_scale_factor,
  )
  if self.device_scale_factor <= 0.0 {
    self.device_scale_factor = 1.0
  }
  self.device_scale_factor
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn set_vsync_enabled(
  self,
  enabled,
) {
  self.vsync_enabled = web_set_vsync_enabled(
    self.canvas_selector,
    self.web_active,
    enabled,
  )
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn is_vsync_enabled(self) {
  self.vsync_enabled = web_is_vsync_enabled(
    self.canvas_selector,
    self.web_active,
    self.vsync_enabled,
  )
  self.vsync_enabled
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn close_window(self) {
  self.close_requested = true
  web_close_window(self.canvas_selector, self.web_active)
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn request_attention(self) {
  self.attention_requests = self.attention_requests + 1
  web_request_attention(self.canvas_selector, self.web_active)
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn set_mouse_touch_fallback(
  self,
  enabled,
) {
  self.mouse_touch_fallback = enabled
  web_set_mouse_touch_fallback(self.canvas_selector, self.web_active, enabled)
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn mouse_touch_fallback_enabled(
  self,
) {
  self.mouse_touch_fallback
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn fullscreen_request_status(
  self,
) {
  let status = web_fullscreen_request_status(
    self.canvas_selector,
    self.web_active,
    async_request_status_to_int(self.fullscreen_request_status),
  )
  self.fullscreen_request_status = async_request_status_from_int(status)
  self.fullscreen_request_status
}

///|
pub impl PlatformDriver for WebCanvasPlatform with fn cursor_mode_request_status(
  self,
) {
  let status = web_cursor_mode_request_status(
    self.canvas_selector,
    self.web_active,
    async_request_status_to_int(self.cursor_mode_request_status),
  )
  self.cursor_mode_request_status = async_request_status_from_int(status)
  self.cursor_mode_request_status
}

///|
pub extend WindowOptions with @moonbitlang/core/debug.Debug::{to_repr}

///|
pub extend WindowOptions with Show::{to_string, output}

///|
pub extend MonitorInfo with @moonbitlang/core/debug.Debug::{to_repr}

///|
pub extend MonitorInfo with Show::{to_string, output}

///|
pub extend FullscreenMode with @moonbitlang/core/debug.Debug::{to_repr}

///|
pub extend FullscreenMode with Show::{to_string, output}

///|
pub extend CursorMode with @moonbitlang/core/debug.Debug::{to_repr}

///|
pub extend CursorMode with Show::{to_string, output}

///|
pub extend AsyncRequestStatus with @moonbitlang/core/debug.Debug::{to_repr}

///|
pub extend AsyncRequestStatus with Show::{to_string, output}

///|
pub extend DesktopGlfwPlatform with PlatformDriver::{
  poll_events,
  mouse_touch_fallback_enabled,
  device_scale_factor,
  set_fullscreen,
  cursor_mode,
  monitor_info,
  is_fullscreen,
  is_vsync_enabled,
  request_attention,
  should_close,
  set_mouse_touch_fallback,
  capture_input,
  close_window,
  initialize,
  fullscreen_request_status,
  cursor_mode_request_status,
  outside_size,
  set_device_scale_factor,
  set_vsync_enabled,
  set_cursor_mode,
}

///|
pub extend WebCanvasPlatform with PlatformDriver::{
  poll_events,
  mouse_touch_fallback_enabled,
  device_scale_factor,
  set_fullscreen,
  cursor_mode,
  monitor_info,
  is_fullscreen,
  is_vsync_enabled,
  request_attention,
  should_close,
  set_mouse_touch_fallback,
  capture_input,
  close_window,
  initialize,
  fullscreen_request_status,
  cursor_mode_request_status,
  outside_size,
  set_device_scale_factor,
  set_vsync_enabled,
  set_cursor_mode,
}