// 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.

///|
/// Standalone button widget struct supporting fluent configuration.
pub struct Button {
  text : String
  shortcut : String
  primary : Bool
  size : @math.Vec2
} derive(Eq, Debug)

///|
/// Create a new button widget with default styling.
pub fn Button::new(text : String) -> Button {
  { text, shortcut: "", primary: false, size: @math.Vec2::zero(), }
}

///|
/// Configure an Apple-grade chiclet keyboard shortcut badge (e.g. "⌘S", "Esc").
pub fn Button::shortcut(self : Button, shortcut : String) -> Button {
  { ..self, shortcut, }
}

///|
/// Configure button as high-contrast cold cobalt primary action.
pub fn Button::primary(self : Button, primary : Bool) -> Button {
  { ..self, primary, }
}

///|
/// Explicitly override the button's layout dimensions.
pub fn Button::size(self : Button, size : @math.Vec2) -> Button {
  { ..self, size, }
}

///|
/// Render the button into the provided UIContext.
pub impl @core.Widget for Button with fn ui(self, ctx : UIContext) -> Response {
  let scale = ctx.style.scale
  let font_size = ctx.style.font_normal * scale
  let text_size = ctx.measure_text(self.text, font_size)
  let text_w = text_size.x
  let has_shortcut = self.shortcut.length() > 0
  let kbd_font_size = ctx.style.font_small * scale
  let kbd_w = if has_shortcut {
    ctx.measure_text(self.shortcut, kbd_font_size).x + 14.0 * scale
  } else {
    0.0
  }

  let min_w = if has_shortcut { 88.0 * scale } else { 68.0 * scale }
  let pad_w = if has_shortcut {
    36.0 * scale
  } else {
    (ctx.style.spacing_sm + ctx.style.radius_md) * 2.0 * scale
  }
  let content_w = if has_shortcut {
    text_w + kbd_w + pad_w
  } else {
    text_w + pad_w
  }
  let auto_w = if content_w > min_w { content_w } else { min_w }
  let w = if self.size.x > 0.0 { self.size.x } else { auto_w }
  let h = if self.size.y > 0.0 {
    self.size.y
  } else {
    ctx.style.control_h_md * scale
  }

  let (id, rect, resp) = ctx.allocate_space(@math.Vec2::new(w, h))
  ctx.register_focusable(id)
  if resp.hovered {
    ctx.set_cursor_icon("pointer")
  }

  // 1.5px Mechanical Press Travel & Tactile Actuation Displacement
  let press_offset = if resp.pressed { 1.5 * scale } else { 0.0 }
  let draw_rect = @math.Rect::new(
    rect.x,
    rect.y + press_offset,
    rect.w,
    rect.h - press_offset,
  )

  // Active Semantic Theme Palette
  let theme = ctx.theme
  let bg_color = if self.primary {
    if resp.pressed {
      theme.accent_pressed
    } else if resp.hovered {
      theme.accent_hover
    } else {
      theme.accent_primary
    }
  } else if resp.pressed {
    theme.bg_surface
  } else if resp.hovered {
    theme.bg_subtle
  } else {
    theme.bg_window
  }

  let border_color = if resp.has_focus() {
    theme.border_focus
  } else if self.primary {
    if resp.pressed {
      theme.accent_deep
    } else {
      theme.accent_pressed
    }
  } else if resp.pressed {
    theme.border_strong
  } else if resp.hovered {
    theme.accent_primary
  } else {
    theme.border_default
  }

  let text_color = if self.primary {
    theme.text_inverse
  } else if resp.pressed {
    theme.text_strong
  } else if resp.hovered {
    theme.text_primary
  } else {
    theme.text_body
  }

  let painter = ctx.painter()
  let radius = ctx.style.radius_md * scale
  painter.add_rect(draw_rect, bg_color, radius)
  let stroke_w = if resp.has_focus() { 1.5 * scale } else { 1.0 * scale }
  painter.add_rect_stroke(draw_rect, border_color, stroke_w, radius)

  if has_shortcut {
    // Left-align text when shortcut badge exists
    let text_x = draw_rect.x + 12.0 * scale
    let text_y = draw_rect.y + (draw_rect.h - font_size) * 0.5
    painter.add_text(
      @math.Vec2::new(text_x, text_y),
      self.text,
      font_size,
      text_color,
    )

    // Chiclet Shortcut Badge (synchronously moves down on press)
    let kbd_h = 18.0 * scale
    let kbd_rect = @math.Rect::new(
      draw_rect.x + draw_rect.w - kbd_w - 10.0 * scale,
      draw_rect.y + (draw_rect.h - kbd_h) * 0.5,
      kbd_w,
      kbd_h,
    )
    let (kbd_bg, kbd_col) = if self.primary {
      (theme.accent_light, theme.text_inverse)
    } else {
      (
        if resp.pressed {
          theme.border_muted
        } else if resp.hovered {
          theme.bg_active
        } else {
          theme.bg_surface
        },
        if resp.hovered {
          theme.text_primary
        } else {
          theme.text_muted
        },
      )
    }
    painter.add_rect(kbd_rect, kbd_bg, ctx.style.radius_sm * scale)
    let sc_w = ctx.measure_text(self.shortcut, kbd_font_size).x
    let kbd_text_x = kbd_rect.x + (kbd_rect.w - sc_w) * 0.5
    let kbd_text_y = kbd_rect.y + (kbd_rect.h - kbd_font_size) * 0.5
    painter.add_text(
      @math.Vec2::new(kbd_text_x, kbd_text_y),
      self.shortcut,
      kbd_font_size,
      kbd_col,
    )
  } else {
    // Center-align text in standard button
    let text_x = draw_rect.x + (draw_rect.w - text_w) * 0.5
    let text_y = draw_rect.y + (draw_rect.h - font_size) * 0.5
    painter.add_text(
      @math.Vec2::new(text_x, text_y),
      self.text,
      font_size,
      text_color,
    )
  }

  resp
}

///|
/// Render an interactive button with modern Studio Light porcelain aesthetic and 1.5px physical mechanical actuation travel.
pub fn button(
  ctx : UIContext,
  text : String,
  shortcut? : String = "",
  primary? : Bool = false,
  size? : @math.Vec2 = @math.Vec2::zero(),
) -> Response {
  ctx.add(Button::new(text).shortcut(shortcut).primary(primary).size(size))
}

///|
/// Render an interactive button with an explicitly specified size.
pub fn button_sized(
  ctx : UIContext,
  text : String,
  size : @math.Vec2,
) -> Response {
  button(ctx, text, size~)
}

///|
/// Render an emphasized primary button with an explicitly specified size.
pub fn button_primary_sized(
  ctx : UIContext,
  text : String,
  size : @math.Vec2,
) -> Response {
  button(ctx, text, primary=true, size~)
}

///|
/// Render an emphasized call-to-action primary button using accent colors.
pub fn button_primary(ctx : UIContext, text : String) -> Response {
  button(ctx, text, primary=true)
}

///|
/// Render an interactive button with a desktop-grade shortcut badge (e.g. "⌘S" or "Esc").
pub fn button_with_shortcut(
  ctx : UIContext,
  text : String,
  shortcut : String,
) -> Response {
  button(ctx, text, shortcut~)
}

///|
/// Render an interactive color preview button.
pub fn color_button(
  ctx : UIContext,
  _id_str : String,
  color : @color.Color,
) -> (Bool, Response) {
  let scale = ctx.style.scale
  let size = 22.0 * scale
  let (id, rect, resp) = ctx.allocate_space(@math.Vec2::new(size, size))
  ctx.register_focusable(id)
  if resp.hovered {
    ctx.set_cursor_icon("pointer")
  }
  let is_focused = resp.has_focus() || ctx.has_focus(id)
  let key_toggle = is_focused &&
    !ctx.input.is_key_consumed(Key::Space) &&
    !ctx.input.is_key_consumed(Key::Enter) &&
    (ctx.input.key_pressed(Key::Space) || ctx.input.key_pressed(Key::Enter))
  if key_toggle {
    ctx.input.consume_key(Key::Space)
    ctx.input.consume_key(Key::Enter)
  }
  let clicked = resp.clicked || key_toggle

  let press_offset = if resp.pressed { 1.0 * scale } else { 0.0 }
  let btn_rect = @math.Rect::new(
    rect.x,
    rect.y + press_offset,
    size,
    size - press_offset,
  )
  let theme = ctx.theme
  let border_color = if is_focused {
    theme.border_focus
  } else if resp.pressed || resp.hovered {
    theme.accent_primary
  } else {
    theme.border_default
  }

  // Draw color swatch with clean white rim
  let swatch_radius = ctx.style.radius_md * scale
  let p = ctx.painter()
  p.add_rect(btn_rect, color, swatch_radius)
  let stroke_w = if is_focused { 2.0 * scale } else { 1.5 * scale }
  p.add_rect_stroke(btn_rect, border_color, stroke_w, swatch_radius)
  if is_focused {
    p.add_rect_stroke(
      btn_rect.expand(2.0 * scale),
      theme.border_focus,
      1.5 * scale,
      swatch_radius + 2.0 * scale,
    )
  }

  (clicked, resp)
}