// 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 segmented control widget supporting fluent configuration.
pub struct SegmentedControl {
  id_salt : String
  options : Array[String]
  selected_index : Int
  height : Double
  width : Double
} derive(Eq, Debug)

///|
/// Create a new segmented control widget.
pub fn SegmentedControl::new(
  id_salt : String,
  options : Array[String],
  selected_index : Int,
) -> SegmentedControl {
  { id_salt, options, selected_index, height: 0.0, width: 0.0, }
}

///|
/// Explicitly configure height dimension.
pub fn SegmentedControl::height(
  self : SegmentedControl,
  height : Double,
) -> SegmentedControl {
  { ..self, height, }
}

///|
/// Explicitly configure width dimension.
pub fn SegmentedControl::width(
  self : SegmentedControl,
  width : Double,
) -> SegmentedControl {
  { ..self, width, }
}

///|
/// Show the segmented control and return (new_selected_index, response).
pub fn SegmentedControl::show(
  self : SegmentedControl,
  ctx : UIContext,
) -> (Int, Response) {
  segmented_control(
    ctx,
    self.id_salt,
    self.options,
    self.selected_index,
    height=self.height,
    width=self.width,
  )
}

///|
/// Render a segmented control widget featuring a recessed porcelain track,
/// a floating white porcelain pill indicator with ambient shadow, and keyboard arrow switching.
pub fn segmented_control(
  ctx : UIContext,
  id_salt : String,
  options : Array[String],
  selected_index : Int,
  height? : Double = 0.0,
  width? : Double = 0.0,
) -> (Int, Response) {
  let count = options.length()
  if count == 0 {
    let (_id, _rect, resp) = ctx.allocate_space(@math.Vec2::zero())
    return (selected_index, resp)
  }

  let scale = ctx.style.scale
  let eff_h = if height > 0.0 {
    height
  } else {
    (ctx.style.control_h_md + ctx.style.radius_xs) * scale
  }
  let font_sz = ctx.style.font_normal * scale
  let pad = 3.0 * scale
  let item_pad_x = ctx.style.spacing_md * scale
  let track_radius = 7.0 * scale
  let pill_radius = 5.0 * scale

  let item_w = if width > 0.0 {
    (width - pad * 2.0) / count.to_double()
  } else {
    let mut max_txt_w = 0.0
    for opt in options {
      let sz = ctx.measure_text(opt, font_sz)
      if sz.x > max_txt_w {
        max_txt_w = sz.x
      }
    }
    max_txt_w + item_pad_x * 2.0
  }

  let total_w = if width > 0.0 {
    width
  } else {
    item_w * count.to_double() + pad * 2.0
  }

  ctx.push_id(id_salt)
  let (id, track_rect, resp) = ctx.allocate_space(
    @math.Vec2::new(total_w, eff_h),
  )
  ctx.pop_id()
  ctx.register_focusable(id)

  let mut current_sel = selected_index
  if current_sel < 0 {
    current_sel = 0
  } else if current_sel >= count {
    current_sel = count - 1
  }

  let is_focused = resp.has_focus() || ctx.has_focus(id)
  if is_focused {
    if ctx.input.key_pressed(Key::ArrowLeft) {
      current_sel = if current_sel > 0 { current_sel - 1 } else { count - 1 }
      ctx.input.consume_key(Key::ArrowLeft)
    }
    if ctx.input.key_pressed(Key::ArrowRight) {
      current_sel = if current_sel < count - 1 { current_sel + 1 } else { 0 }
      ctx.input.consume_key(Key::ArrowRight)
    }
    if ctx.input.key_pressed(Key::Home) {
      current_sel = 0
      ctx.input.consume_key(Key::Home)
    }
    if ctx.input.key_pressed(Key::End) {
      current_sel = count - 1
      ctx.input.consume_key(Key::End)
    }
  }

  let theme = ctx.theme
  if is_focused {
    ctx
    .painter()
    .add_rect_stroke(
      track_rect.expand(2.0 * scale),
      theme.border_focus,
      1.5 * scale,
      track_radius + 2.0 * scale,
    )
  }

  ctx.painter().add_rect(track_rect, theme.bg_subtle, track_radius)
  ctx
  .painter()
  .add_rect_stroke(track_rect, theme.border_muted, 1.0 * scale, track_radius)

  let pill_h = track_rect.h - pad * 2.0
  let pill_x = track_rect.x + pad + current_sel.to_double() * item_w
  let pill_y = track_rect.y + pad
  let pill_rect = @math.Rect::new(pill_x, pill_y, item_w, pill_h)

  ctx
  .painter()
  .add_rect(
    @math.Rect::new(pill_x, pill_y + 1.0 * scale, item_w, pill_h),
    theme.shadow,
    pill_radius,
  )
  ctx.painter().add_rect(pill_rect, theme.bg_window, pill_radius)
  ctx
  .painter()
  .add_rect_stroke(pill_rect, theme.border_default, 1.0 * scale, pill_radius)

  for i = 0; i < count; i = i + 1 {
    let opt_x = track_rect.x + pad + i.to_double() * item_w
    let opt_rect = @math.Rect::new(opt_x, pill_y, item_w, pill_h)

    let is_hovered = ctx.is_hovered(opt_rect)
    if is_hovered {
      ctx.set_cursor_icon("pointer")
      if i != current_sel {
        ctx.painter().add_rect(opt_rect, theme.bg_hover, pill_radius)
      }
      if ctx.input.mouse_pressed {
        current_sel = i
        ctx.request_focus(id)
      }
    }

    let text_col = if i == current_sel {
      theme.text_strong
    } else if is_hovered {
      theme.text_primary
    } else {
      theme.text_secondary
    }

    let text_sz = ctx.measure_text(options[i], font_sz)
    let text_pos = @math.Vec2::new(
      opt_x + (item_w - text_sz.x) * 0.5,
      pill_y + (pill_h - text_sz.y) * 0.5,
    )
    ctx.painter().add_text(text_pos, options[i], font_sz, text_col)
  }

  (current_sel, resp)
}