///|
/// 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 output(self, logger) {
  logger.write_object(to_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 output(self, logger) {
  logger.write_object(to_repr(self))
}

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

///|
pub impl Show for FullscreenMode with output(self, logger) {
  logger.write_object(to_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 output(self, logger) {
  logger.write_object(to_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 output(self, logger) {
  logger.write_object(to_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 trait PlatformDriver {
  /// Ebiten ref: UserInterface.init / Run
  initialize(Self, options : WindowOptions) -> Unit raise

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

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

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

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

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

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

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

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

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

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

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

  /// Async request status for fullscreen and cursor mode
  fullscreen_request_status(Self) -> AsyncRequestStatus
  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 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 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 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 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 capture_input(self, tick) {
  self.current_input = desktop_native_capture_input(self.native_active, tick)
  self.current_input
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with 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 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 is_fullscreen(self) {
  self.fullscreen = desktop_native_is_fullscreen(
    self.native_active,
    self.fullscreen,
  )
  self.fullscreen
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with 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 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 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 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 set_vsync_enabled(
  self,
  enabled,
) {
  self.vsync_enabled = desktop_native_set_vsync_enabled(
    self.native_active,
    enabled,
  )
}

///|
pub impl PlatformDriver for DesktopGlfwPlatform with 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 close_window(self) {
  self.close_requested = true
  desktop_native_close_window(self.native_active)
}

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

///|
pub impl PlatformDriver for DesktopGlfwPlatform with 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 mouse_touch_fallback_enabled(
  self,
) {
  self.mouse_touch_fallback
}

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

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

///|
pub impl PlatformDriver for WebCanvasPlatform with 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 poll_events(self) {
  if self.initialized {
    web_poll(self.web_active)
    self.poll_count = self.poll_count + 1
  }
}

///|
pub impl PlatformDriver for WebCanvasPlatform with 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 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 capture_input(self, tick) {
  self.current_input = web_capture_input(self.web_active, tick)
  self.current_input
}

///|
pub impl PlatformDriver for WebCanvasPlatform with 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 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 is_fullscreen(self) {
  self.fullscreen = web_is_fullscreen(
    self.canvas_selector,
    self.web_active,
    self.fullscreen,
  )
  self.fullscreen
}

///|
pub impl PlatformDriver for WebCanvasPlatform with 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 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 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 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 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 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 close_window(self) {
  self.close_requested = true
  web_close_window(self.canvas_selector, self.web_active)
}

///|
pub impl PlatformDriver for WebCanvasPlatform with 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 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 mouse_touch_fallback_enabled(
  self,
) {
  self.mouse_touch_fallback
}

///|
pub impl PlatformDriver for WebCanvasPlatform with 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 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
}