// Copyright 2026 Ling71671
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Render a top-level horizontal application menu bar in Studio Light style.
/// Spans the available width with a standard 28.0px height.
pub fn menu_bar(ctx : UIContext, content : (UIContext) -> Unit) -> Unit {
  let scale = ctx.style.scale
  let bar_h = (ctx.style.control_h_sm + ctx.style.spacing_xs) * scale
  let bar_w = ctx.available_width()
  let bar_pos = ctx.cursor()
  let bar_rect = @math.Rect::new(bar_pos.x, bar_pos.y, bar_w, bar_h)

  // 1. Menu bar background and subtle bottom divider line
  ctx.painter().add_rect(bar_rect, @color.Color::bg_surface(), 0.0)
  ctx
  .painter()
  .add_line(
    @math.Vec2::new(bar_rect.x, bar_rect.y + bar_h),
    @math.Vec2::new(bar_rect.x + bar_w, bar_rect.y + bar_h),
    @color.Color::border_muted(),
    1.0,
  )

  // 2. Lay out items horizontally inside the menu bar
  let prev_cursor = ctx.cursor()
  let prev_avail_w = ctx.available_width()
  let prev_spacing = ctx.item_spacing()

  ctx.set_cursor(
    @math.Vec2::new(bar_pos.x + 8.0 * scale, bar_pos.y + 3.0 * scale),
  )
  ctx.set_available_width(bar_w - 16.0 * scale)
  ctx.set_item_spacing(@math.Vec2::new(4.0 * scale, 0.0))

  // Horizontal layout scope for menu triggers
  ctx.horizontal(content)

  // Restore cursor below menu bar
  ctx.set_cursor(@math.Vec2::new(prev_cursor.x, bar_pos.y + bar_h))
  ctx.set_available_width(prev_avail_w)
  ctx.set_item_spacing(prev_spacing)
}

///|
/// Render a top-level menu dropdown trigger (e.g. "文件", "视图").
/// When open, it renders its child menu items on the deferred foreground layer.
pub fn menu(
  ctx : UIContext,
  title : String,
  content : (UIContext) -> Unit,
) -> Unit {
  let scale = ctx.style.scale
  let font_nm = ctx.style.font_normal * scale
  let menu_id = ctx.id_stack.derive_id("menu::" + title)
  let text_size = ctx.measure_text(title, font_nm)
  let btn_w = text_size.x + 16.0 * scale
  let btn_h = (ctx.style.control_h_sm - ctx.style.radius_xs) * scale

  ctx.push_id(title)
  let (id, btn_rect, _) = ctx.allocate_space(@math.Vec2::new(btn_w, btn_h))
  ctx.pop_id()
  ctx.register_focusable(id)
  let is_focused = ctx.has_focus(id)

  let is_open = ctx.open_menu_id() == menu_id
  let hovered = ctx.is_hovered(btn_rect)
  if hovered {
    ctx.set_cursor_icon("pointer")
  }

  // Keyboard: Enter / Space / ArrowDown toggles the dropdown while the
  // trigger holds focus; Escape closes it.
  let key_toggle = is_focused &&
    (
      ctx.input.key_pressed(Key::Enter) ||
      ctx.input.key_pressed(Key::Space) ||
      ctx.input.key_pressed(Key::ArrowDown)
    )
  if key_toggle {
    ctx.input.consume_key(Key::Enter)
    ctx.input.consume_key(Key::Space)
    ctx.input.consume_key(Key::ArrowDown)
    if is_open {
      ctx.set_open_menu_id(Id::zero())
    } else {
      ctx.set_open_menu_id(menu_id)
    }
  }

  // Desktop Hover-to-Switch interaction:
  // If a menu is ALREADY open, moving the pointer over another menu trigger automatically
  // switches to open that menu!
  if ctx.open_menu_id() != Id::zero() &&
    ctx.open_menu_id() != menu_id &&
    hovered {
    ctx.set_open_menu_id(menu_id)
  } else if hovered && ctx.input.mouse_pressed {
    if is_open {
      ctx.set_open_menu_id(Id::zero())
    } else {
      ctx.set_open_menu_id(menu_id)
    }
  }

  let currently_open = ctx.open_menu_id() == menu_id

  // Escape closes the open dropdown
  if currently_open && ctx.input.key_pressed(Key::Escape) {
    ctx.input.consume_key(Key::Escape)
    ctx.set_open_menu_id(Id::zero())
  }

  // Render the menu bar trigger button
  let btn_bg = if currently_open {
    @color.Color::bg_active()
  } else if hovered {
    @color.Color::bg_subtle()
  } else {
    @color.Color::transparent()
  }
  let btn_text_col = if currently_open {
    @color.Color::accent_primary()
  } else if hovered {
    @color.Color::text_primary()
  } else {
    @color.Color::text_body()
  }

  let radius = ctx.style.radius_sm * scale
  if currently_open || hovered {
    ctx.painter().add_rect(btn_rect, btn_bg, radius)
  }
  if is_focused {
    ctx
    .painter()
    .add_rect_stroke(btn_rect, @color.Color::border_focus(), 1.0, radius)
  }
  ctx
  .painter()
  .add_text(
    @math.Vec2::new(
      btn_rect.x + 8.0 * scale,
      btn_rect.y + (btn_h - font_nm) * 0.5,
    ),
    title,
    font_nm,
    btn_text_col,
  )

  // If this menu is open, render the dropdown menu panel
  if currently_open {
    ctx.begin_foreground()

    let pad = 4.0 * scale
    let popup_w = 170.0 * scale
    let mut popup_x = btn_rect.x
    let popup_y = btn_rect.y + btn_rect.h + 3.0 * scale

    // Prevent spilling off-screen to the right if near viewport edge
    if popup_x + popup_w > ctx.available_width() {
      let clamped = ctx.available_width() - popup_w - 4.0 * scale
      if clamped > 4.0 * scale {
        popup_x = clamped
      }
    }

    let prev_cursor = ctx.cursor()
    let prev_avail_w = ctx.available_width()
    let prev_spacing = ctx.item_spacing()

    ctx.set_cursor(@math.Vec2::new(popup_x + pad, popup_y + pad))
    ctx.set_available_width(popup_w - pad * 2.0)
    ctx.set_item_spacing(@math.Vec2::new(0.0, 2.0 * scale))

    // Temporary draw list to capture items while determining exact height
    let item_draw_list = @draw.DrawList::new()
    let saved_dl = ctx.layers.draw_list()
    ctx.layers.set_draw_list(item_draw_list)

    ctx.vertical(content)

    ctx.layers.set_draw_list(saved_dl)

    let content_h = ctx.cursor().y - (popup_y + pad)
    let total_h = if content_h > 0.0 { content_h + pad } else { 24.0 }
    let menu_rect = @math.Rect::new(popup_x, popup_y, popup_w, total_h)

    // Block hover on lower layers
    ctx.block_hover(menu_rect)

    // Outside click dismiss: if clicked outside both the menu card and trigger button
    if ctx.input.mouse_pressed && !ctx.is_hovered(menu_rect) && !hovered {
      ctx.set_open_menu_id(Id::zero())
    }

    // Elevation shadow
    let shadow_rect = @math.Rect::new(
      menu_rect.x,
      menu_rect.y + 2.0,
      menu_rect.w,
      menu_rect.h,
    )
    let menu_radius = ctx.style.radius_md
    ctx
    .painter()
    .add_rect(shadow_rect, @color.Color::shadow_ambient(), menu_radius)

    // Card background and border
    ctx.painter().add_rect(menu_rect, @color.Color::bg_window(), menu_radius)
    ctx
    .painter()
    .add_rect_stroke(
      menu_rect,
      @color.Color::border_default(),
      1.0,
      menu_radius,
    )

    // Append items on top of background
    ctx.painter().append(item_draw_list)

    // Restore context state
    ctx.set_cursor(prev_cursor)
    ctx.set_available_width(prev_avail_w)
    ctx.set_item_spacing(prev_spacing)

    ctx.end_foreground()
  }
}

///|
/// Render a single item inside an active menu dropdown.
/// Supports an optional keyboard shortcut (e.g. "⌘N") aligned to the right.
pub fn menu_item(
  ctx : UIContext,
  label : String,
  shortcut? : String = "",
  disabled? : Bool = false,
) -> Response {
  let scale = ctx.style.scale
  let item_h = 24.0 * scale
  let item_w = ctx.available_width()

  ctx.push_id(label)
  let (id, rect, resp) = ctx.allocate_space(@math.Vec2::new(item_w, item_h))
  ctx.pop_id()
  ctx.register_focusable(id)
  let is_focused = resp.has_focus() || ctx.has_focus(id)

  let is_hovered = ctx.is_hovered(rect) && !disabled

  let item_radius = ctx.style.radius_sm * scale
  let font_nm = ctx.style.font_normal * scale
  let font_sm = ctx.style.font_small * scale
  if is_hovered {
    ctx.set_cursor_icon("pointer")
    ctx.painter().add_rect(rect, @color.Color::bg_surface(), item_radius)
  }
  if is_focused {
    ctx
    .painter()
    .add_rect_stroke(rect, @color.Color::border_focus(), 1.0, item_radius)
  }

  let key_activate = is_focused &&
    !disabled &&
    (ctx.input.key_pressed(Key::Space) || ctx.input.key_pressed(Key::Enter))
  if key_activate {
    ctx.input.consume_key(Key::Space)
    ctx.input.consume_key(Key::Enter)
  }

  let clicked = if disabled {
    false
  } else {
    (is_hovered && (ctx.input.mouse_pressed || resp.clicked)) || key_activate
  }
  if clicked {
    ctx.set_open_menu_id(Id::zero())
  }

  let text_col = if disabled {
    @color.Color::text_disabled()
  } else if is_hovered {
    @color.Color::accent_primary()
  } else {
    @color.Color::text_primary()
  }

  // Left-aligned label
  let text_y = rect.y + (item_h - font_nm) * 0.5
  ctx
  .painter()
  .add_text(
    @math.Vec2::new(rect.x + 8.0 * scale, text_y),
    label,
    font_nm,
    text_col,
  )

  // Right-aligned shortcut badge
  if !shortcut.is_empty() {
    let sc_size = ctx.measure_text(shortcut, font_sm)
    let sc_x = rect.x + item_w - sc_size.x - 8.0 * scale
    let sc_y = rect.y + (item_h - font_sm) * 0.5
    let sc_col = if disabled {
      @color.Color::text_disabled()
    } else if is_hovered {
      @color.Color::accent_primary()
    } else {
      @color.Color::text_muted()
    }
    ctx
    .painter()
    .add_text(@math.Vec2::new(sc_x, sc_y), shortcut, font_sm, sc_col)
  }

  Response::new(id, rect, is_hovered, clicked, resp.pressed, false)
}

///|
/// Render a clean divider line between menu item groups.
pub fn menu_separator(ctx : UIContext) -> Unit {
  let scale = ctx.style.scale
  let sep_h = 7.0 * scale
  let item_w = ctx.available_width()
  let (_id, rect, _) = ctx.allocate_space(@math.Vec2::new(item_w, sep_h))
  let line_y = rect.y + 3.0 * scale
  let pad_x = 4.0 * scale
  let stroke_w = 1.0 * scale
  ctx
  .painter()
  .add_line(
    @math.Vec2::new(rect.x + pad_x, line_y),
    @math.Vec2::new(rect.x + item_w - pad_x, line_y),
    @color.Color::border_muted(),
    stroke_w,
  )
}