/*
 * Copyright (c) 2023-2026 Huawei Device Co., Ltd.
 * 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.
 */

import curves from '@ohos.curves';
import { KeyCode } from '@ohos.multimodalInput.keyCode';
import util from '@ohos.util';
import { LengthMetrics, LengthUnit } from '@ohos.arkui.node';
import I18n from '@ohos.i18n';
import uiMaterial from '@ohos.arkui.uiMaterial';
import { EnvironmentCallback } from '@kit.AbilityKit';
import deviceInfo from '@ohos.deviceInfo';
import { CustomLayoutAlgorithm, DynamicLayout, LayoutConstraint } from '@kit.ArkUI';

const MIN_ITEM_COUNT = 2
const MAX_ITEM_COUNT = 5
const DEFAULT_MAX_FONT_SCALE: number = 1
const MAX_MAX_FONT_SCALE: number = 2
const MIN_MAX_FONT_SCALE: number = 1
const RESOURCE_TYPE_FLOAT = 10002;
const RESOURCE_TYPE_INTEGER = 10007;
// Space character for selected accessibility description - prevents screen readers from announcing
const ACCESSIBILITY_SELECTED_DESCRIPTION = ' ';
const ACCESSIBILITY_DEFAULT_DESCRIPTION = '';
const CAPSULE_FOCUS_SELECTED_OFFSET: number = 4;

interface SegmentButtonThemeInterface {
  SEGMENT_TEXT_VERTICAL_PADDING: Resource;
  SEGMENT_TEXT_HORIZONTAL_PADDING: Resource;
  SEGMENT_TEXT_CAPSULE_VERTICAL_PADDING: Resource;
  SEGMENT_BUTTON_FOCUS_CUSTOMIZED_BG_COLOR: ResourceColor;
  FONT_COLOR: ResourceColor,
  TAB_SELECTED_FONT_COLOR: ResourceColor,
  CAPSULE_SELECTED_FONT_COLOR: ResourceColor,
  FONT_SIZE: DimensionNoPercentage,
  SELECTED_FONT_SIZE: DimensionNoPercentage,
  ADAPTIVE_ITEM_FONT_SIZE: DimensionNoPercentage,
  BACKGROUND_COLOR: ResourceColor,
  TAB_SELECTED_BACKGROUND_COLOR: ResourceColor,
  CAPSULE_SELECTED_BACKGROUND_COLOR: ResourceColor,
  FOCUS_BORDER_COLOR: ResourceColor,
  HOVER_COLOR: ResourceColor,
  PRESS_COLOR: ResourceColor,
  BACKGROUND_BLUR_STYLE: Resource,
  CONSTRAINT_SIZE_MIN_HEIGHT: DimensionNoPercentage,
  SEGMENT_BUTTON_MIN_FONT_SIZE: DimensionNoPercentage,
  SEGMENT_BUTTON_NORMAL_BORDER_RADIUS: Length | BorderRadiuses | LocalizedBorderRadiuses,
  SEGMENT_ITEM_TEXT_OVERFLOW: Resource,
  SEGMENT_BUTTON_FOCUS_TEXT_COLOR: ResourceColor,
  SEGMENT_FOCUS_STYLE_CUSTOMIZED: Resource,
  SEGMENT_BUTTON_CONTAINER_SHAPE: Resource,
  SEGMENT_BUTTON_SELECTED_BACKGROUND_SHAPE: Resource,
  SEGMENT_BUTTON_UNSELECTED_FONT_WEIGHT: Resource,
  SEGMENT_BUTTON_BORDER_WIDTH: DimensionNoPercentage,
  SEGMENT_BUTTON_BORDER_COLOR: ResourceColor,
}

const segmentButtonTheme: SegmentButtonThemeInterface = {
  FONT_COLOR: $r('sys.color.segment_button_unselected_text_color'),
  TAB_SELECTED_FONT_COLOR: $r('sys.color.segment_button_checked_text_color'),
  CAPSULE_SELECTED_FONT_COLOR: $r('sys.color.ohos_id_color_foreground_contrary'),
  FONT_SIZE: $r('sys.float.segment_button_unselected_text_size'),
  SELECTED_FONT_SIZE: $r('sys.float.segment_button_checked_text_size'),
  ADAPTIVE_ITEM_FONT_SIZE: $r('sys.float.Caption_M'),
  BACKGROUND_COLOR: $r('sys.color.segment_button_backboard_color'),
  TAB_SELECTED_BACKGROUND_COLOR: $r('sys.color.segment_button_checked_foreground_color'),
  CAPSULE_SELECTED_BACKGROUND_COLOR: $r('sys.color.ohos_id_color_emphasize'),
  FOCUS_BORDER_COLOR: $r('sys.color.ohos_id_color_focused_outline'),
  HOVER_COLOR: $r('sys.color.segment_button_hover_color'),
  PRESS_COLOR: $r('sys.color.segment_button_press_color'),
  BACKGROUND_BLUR_STYLE: $r('sys.float.segment_button_background_blur_style'),
  CONSTRAINT_SIZE_MIN_HEIGHT: $r('sys.float.segment_button_height'),
  SEGMENT_BUTTON_MIN_FONT_SIZE: $r('sys.float.segment_button_min_font_size'),
  SEGMENT_BUTTON_NORMAL_BORDER_RADIUS: $r('sys.float.segment_button_normal_border_radius'),
  SEGMENT_ITEM_TEXT_OVERFLOW: $r('sys.float.segment_marquee'),
  SEGMENT_BUTTON_FOCUS_TEXT_COLOR: $r('sys.color.segment_button_focus_text_primary'),
  SEGMENT_TEXT_HORIZONTAL_PADDING: $r('sys.float.segment_button_text_l_r_padding'),
  SEGMENT_TEXT_VERTICAL_PADDING: $r('sys.float.segment_button_text_u_d_padding'),
  SEGMENT_TEXT_CAPSULE_VERTICAL_PADDING: $r('sys.float.segment_button_text_capsule_u_d_padding'),
  SEGMENT_BUTTON_FOCUS_CUSTOMIZED_BG_COLOR: $r('sys.color.segment_button_focus_backboard_primary'),
  SEGMENT_FOCUS_STYLE_CUSTOMIZED: $r('sys.float.segment_focus_control'),
  SEGMENT_BUTTON_CONTAINER_SHAPE: $r('sys.float.segmentbutton_container_shape'),
  SEGMENT_BUTTON_SELECTED_BACKGROUND_SHAPE: $r('sys.float.segmentbutton_selected_background_shape'),
  SEGMENT_BUTTON_UNSELECTED_FONT_WEIGHT: $r('sys.float.segment_button_unselected_font_weight'),
  SEGMENT_BUTTON_BORDER_WIDTH: $r('sys.float.segment_button_border_width'),
  SEGMENT_BUTTON_BORDER_COLOR: $r('sys.color.segment_button_border_color'),
}

interface Point {
  x: number
  y: number
}

function nearEqual(first: number, second: number): boolean {
  return Math.abs(first - second) < 0.001
}

function validateLengthMetrics(value: LengthMetrics | undefined, defaultValue: LengthMetrics): LengthMetrics {
  const actualValue = value ?? defaultValue;
  return (actualValue.value < 0 || actualValue.unit === LengthUnit.PERCENT) ? defaultValue : actualValue;
}

function initFontWeight(defaultValue: FontWeight) {
  const value = LengthMetrics.resource(segmentButtonTheme.SEGMENT_BUTTON_UNSELECTED_FONT_WEIGHT).value;
  switch (value) {
    case 100:
      return FontWeight.Lighter;
    case 400:
      return FontWeight.Regular;
    case 500:
      return FontWeight.Medium;
    case 700:
      return FontWeight.Bold;
    case 900:
      return FontWeight.Bolder;
    default:
      return defaultValue;
  }
}

export interface SegmentButtonTextItem {
  text: ResourceStr
  accessibilityLevel?: string
  accessibilityDescription?: ResourceStr
}

interface SegmentButtonIconItem {
  icon: ResourceStr,
  iconAccessibilityText?: ResourceStr
  selectedIcon: ResourceStr
  selectedIconAccessibilityText?: ResourceStr
  accessibilityLevel?: string
  accessibilityDescription?: ResourceStr
}

interface SegmentButtonIconTextItem {
  icon: ResourceStr,
  iconAccessibilityText?: ResourceStr
  selectedIcon: ResourceStr,
  selectedIconAccessibilityText?: ResourceStr
  text: ResourceStr
  accessibilityLevel?: string
  accessibilityDescription?: ResourceStr
}

type DimensionNoPercentage = PX | VP | FP | LPX | Resource

interface CommonSegmentButtonOptions {
  fontColor?: ResourceColor
  selectedFontColor?: ResourceColor
  fontSize?: DimensionNoPercentage
  selectedFontSize?: DimensionNoPercentage
  fontWeight?: FontWeight
  selectedFontWeight?: FontWeight
  backgroundColor?: ResourceColor
  selectedBackgroundColor?: ResourceColor
  imageSize?: SizeOptions
  buttonPadding?: Padding | Dimension
  textPadding?: Padding | Dimension
  localizedTextPadding?: LocalizedPadding
  localizedButtonPadding?: LocalizedPadding
  backgroundBlurStyle?: BlurStyle
  direction?: Direction
  borderRadiusMode?: BorderRadiusMode
  backgroundBorderRadius?: LengthMetrics
  itemBorderRadius?: LengthMetrics
  backgroundSystemMaterial?: uiMaterial.Material
}

export type ItemRestriction<T> = [T, T, T?, T?, T?]
export type SegmentButtonItemTuple = ItemRestriction<SegmentButtonTextItem> |
ItemRestriction<SegmentButtonIconItem> | ItemRestriction<SegmentButtonIconTextItem>
export type SegmentButtonItemArray = Array<SegmentButtonTextItem> |
Array<SegmentButtonIconItem> | Array<SegmentButtonIconTextItem>

export interface TabSegmentButtonConstructionOptions extends CommonSegmentButtonOptions {
  buttons: ItemRestriction<SegmentButtonTextItem>
}

export interface CapsuleSegmentButtonConstructionOptions extends CommonSegmentButtonOptions {
  buttons: SegmentButtonItemTuple
  multiply?: boolean
}

export interface TabSegmentButtonOptions extends TabSegmentButtonConstructionOptions {
  type: 'tab',
}

export interface CapsuleSegmentButtonOptions extends CapsuleSegmentButtonConstructionOptions {
  type: 'capsule'
}

export enum BorderRadiusMode {
  /**
   * DEFAULT Mode, the framework automatically calculates the border radius
   */
  DEFAULT = 0,

  /**
   * CUSTOM Mode, the developer sets the border radius
   */
  CUSTOM = 1
}

interface SegmentButtonItemOptionsConstructorOptions {
  icon?: ResourceStr
  iconAccessibilityText?: ResourceStr
  selectedIcon?: ResourceStr
  selectedIconAccessibilityText?: ResourceStr
  text?: ResourceStr
  accessibilityLevel?: string
  accessibilityDescription?: ResourceStr
}

@Observed
class SegmentButtonItemOptions {
  public icon?: ResourceStr
  public iconAccessibilityText?: ResourceStr
  public selectedIcon?: ResourceStr
  public selectedIconAccessibilityText?: ResourceStr
  public text?: ResourceStr
  public accessibilityLevel?: string
  public accessibilityDescription?: ResourceStr

  constructor(options: SegmentButtonItemOptionsConstructorOptions) {
    this.icon = options.icon
    this.selectedIcon = options.selectedIcon
    this.text = options.text
    this.iconAccessibilityText = options.iconAccessibilityText
    this.selectedIconAccessibilityText = options.selectedIconAccessibilityText
    this.accessibilityLevel = options.accessibilityLevel
    this.accessibilityDescription = options.accessibilityDescription
  }
}

@Observed
export class SegmentButtonItemOptionsArray extends Array<SegmentButtonItemOptions> {
  public changeStartIndex: number | undefined = void 0
  public deleteCount: number | undefined = void 0
  public addLength: number | undefined = void 0

  constructor(length: number)

  constructor(elements: SegmentButtonItemTuple)

  constructor(elementsOrLength: SegmentButtonItemTuple | number) {

    super(typeof elementsOrLength === 'number' ? elementsOrLength : 0);

    if (typeof elementsOrLength !== 'number' && elementsOrLength !== void 0) {
      super.push(...elementsOrLength.map((element?: SegmentButtonTextItem | SegmentButtonIconItem |
      SegmentButtonIconTextItem) => new SegmentButtonItemOptions(element as
      SegmentButtonItemOptionsConstructorOptions)))
    }
  }

  push(...items: SegmentButtonItemArray): number {
    if (this.length + items.length > MAX_ITEM_COUNT) {
      console.warn('Exceeded the maximum number of elements (5).')
      return this.length
    }
    this.changeStartIndex = this.length
    this.deleteCount = 0
    this.addLength = items.length
    return super.push(...items.map((element: SegmentButtonItemOptionsConstructorOptions) =>
    new SegmentButtonItemOptions(element)))
  }

  pop() {
    if (this.length <= MIN_ITEM_COUNT) {
      console.warn('Below the minimum number of elements (2).')
      return void 0
    }
    this.changeStartIndex = this.length - 1
    this.deleteCount = 1
    this.addLength = 0
    return super.pop()
  }

  shift() {
    if (this.length <= MIN_ITEM_COUNT) {
      console.warn('Below the minimum number of elements (2).')
      return void 0
    }
    this.changeStartIndex = 0
    this.deleteCount = 1
    this.addLength = 0
    return super.shift()
  }

  unshift(...items: SegmentButtonItemArray): number {
    if (this.length + items.length > MAX_ITEM_COUNT) {
      console.warn('Exceeded the maximum number of elements (5).')
      return this.length
    }
    if (items.length > 0) {
      this.changeStartIndex = 0
      this.deleteCount = 0
      this.addLength = items.length
    }
    return super.unshift(...items.map((element: SegmentButtonItemOptionsConstructorOptions) =>
    new SegmentButtonItemOptions(element)))
  }

  splice(start: number, deleteCount: number, ...items: SegmentButtonItemOptions[]): SegmentButtonItemOptions[] {
    let length = (this.length - deleteCount) < 0 ? 0 : (this.length - deleteCount)
    length += items.length
    if (length < MIN_ITEM_COUNT) {
      console.warn('Below the minimum number of elements (2).')
      return []
    }
    if (length > MAX_ITEM_COUNT) {
      console.warn('Exceeded the maximum number of elements (5).')
      return []
    }
    this.changeStartIndex = start
    this.deleteCount = deleteCount
    this.addLength = items.length
    return super.splice(start, deleteCount, ...items)
  }

  static create(elements: SegmentButtonItemTuple): SegmentButtonItemOptionsArray {
    return new SegmentButtonItemOptionsArray(elements)
  }
}

@Observed
export class SegmentButtonOptions {
  public type: 'tab' | 'capsule'
  public multiply: boolean = false
  public fontColor: ResourceColor
  public selectedFontColor: ResourceColor
  public fontSize: DimensionNoPercentage
  public selectedFontSize: DimensionNoPercentage
  public fontWeight: FontWeight
  public selectedFontWeight: FontWeight
  public backgroundColor: ResourceColor
  public selectedBackgroundColor: ResourceColor
  public imageSize: SizeOptions
  public buttonPadding: Padding | Dimension | undefined
  public textPadding: Padding | Dimension | undefined
  public componentPadding: Padding | Dimension
  public localizedTextPadding?: LocalizedPadding
  public localizedButtonPadding?: LocalizedPadding
  public showText: boolean = false
  public showIcon: boolean = false
  public hasFontSize: boolean = false;
  public hasSelectedFontSize: boolean = false;
  public iconTextRadius?: number
  public iconTextBackgroundRadius?: number
  public backgroundBlurStyle: BlurStyle
  public direction?: Direction
  public borderRadiusMode?: BorderRadiusMode
  public backgroundBorderRadius?: LengthMetrics
  public itemBorderRadius?: LengthMetrics
  public backgroundSystemMaterial?: uiMaterial.Material
  private _buttons: SegmentButtonItemOptionsArray | undefined = void 0

  get buttons() {
    return this._buttons
  }

  set buttons(val) {
    if (this._buttons !== void 0 && this._buttons !== val) {
      this.onButtonsChange?.()
    }
    this._buttons = val
  }

  public onButtonsChange?: () => void

  constructor(options: TabSegmentButtonOptions | CapsuleSegmentButtonOptions) {
    this.fontColor = options.fontColor ?? segmentButtonTheme.FONT_COLOR
    this.selectedFontColor = options.selectedFontColor ?? segmentButtonTheme.TAB_SELECTED_FONT_COLOR
    this.fontSize = options.fontSize ?? segmentButtonTheme.FONT_SIZE;
    this.selectedFontSize = options.selectedFontSize ?? segmentButtonTheme.SELECTED_FONT_SIZE;
    this.hasFontSize = options.fontSize !== undefined ? true : false;
    this.hasSelectedFontSize = options.selectedFontSize !== undefined ? true : false;
    this.fontWeight = options.fontWeight ?? initFontWeight(FontWeight.Regular)
    this.selectedFontWeight = options.selectedFontWeight ?? FontWeight.Medium
    this.backgroundColor = options.backgroundColor ?? segmentButtonTheme.BACKGROUND_COLOR
    this.selectedBackgroundColor = options.selectedBackgroundColor ?? segmentButtonTheme.TAB_SELECTED_BACKGROUND_COLOR
    this.imageSize = options.imageSize ?? { width: 24, height: 24 }
    this.buttonPadding = options.buttonPadding
    this.textPadding = options.textPadding
    this.type = options.type
    this.backgroundBlurStyle =
      options.backgroundBlurStyle ??
        LengthMetrics.resource(segmentButtonTheme.BACKGROUND_BLUR_STYLE).value as BlurStyle;
    this.localizedTextPadding = options.localizedTextPadding
    this.localizedButtonPadding = options.localizedButtonPadding
    this.direction = options.direction ?? Direction.Auto
    this.borderRadiusMode = options.borderRadiusMode ?? BorderRadiusMode.DEFAULT
    if (this.borderRadiusMode !== BorderRadiusMode.DEFAULT &&
      this.borderRadiusMode !== BorderRadiusMode.CUSTOM) {
      this.borderRadiusMode = BorderRadiusMode.DEFAULT;
    }
    this.backgroundBorderRadius = validateLengthMetrics(
      options.backgroundBorderRadius,
      LengthMetrics.resource(segmentButtonTheme.SEGMENT_BUTTON_CONTAINER_SHAPE)
    );
    this.itemBorderRadius = validateLengthMetrics(
      options.itemBorderRadius,
      LengthMetrics.resource(segmentButtonTheme.SEGMENT_BUTTON_SELECTED_BACKGROUND_SHAPE)
    );
    this.buttons = new SegmentButtonItemOptionsArray(options.buttons)
    if (this.type === 'capsule') {
      this.multiply = (options as CapsuleSegmentButtonOptions).multiply ?? false
      this.onButtonsUpdated();
      this.selectedFontColor = options.selectedFontColor ?? segmentButtonTheme.CAPSULE_SELECTED_FONT_COLOR
      this.selectedBackgroundColor = options.selectedBackgroundColor ??
        segmentButtonTheme.CAPSULE_SELECTED_BACKGROUND_COLOR
    } else {
      this.showText = true
    }
    let themePadding = LengthMetrics.resource($r('sys.float.padding_level1')).value;
    this.componentPadding = this.multiply ? 0 : themePadding;
    let info = uiMaterial.getMaterialInfo();
    if (info.state === uiMaterial.MaterialState.ENABLE && !options.backgroundSystemMaterial) {
      this.backgroundSystemMaterial = new uiMaterial.ImmersiveMaterial({
        style: uiMaterial.ImmersiveStyle.THIN
      });
    } else if (info.state !== uiMaterial.MaterialState.DISABLE) {
      this.backgroundSystemMaterial = options.backgroundSystemMaterial;
    }
  }

  public onButtonsUpdated() {
    this.buttons?.forEach(button => {
      this.showText ||= button.text !== void 0;
      this.showIcon ||= button.icon !== void 0 || button.selectedIcon !== void 0;
    })
    if (this.showText && this.showIcon) {
      this.iconTextRadius = 12;
      this.iconTextBackgroundRadius = 14;
    }
  }

  static tab(options: TabSegmentButtonConstructionOptions): SegmentButtonOptions {
    return new SegmentButtonOptions({
      type: 'tab',
      buttons: options.buttons,
      fontColor: options.fontColor,
      selectedFontColor: options.selectedFontColor,
      fontSize: options.fontSize,
      selectedFontSize: options.selectedFontSize,
      fontWeight: options.fontWeight,
      selectedFontWeight: options.selectedFontWeight,
      backgroundColor: options.backgroundColor,
      selectedBackgroundColor: options.selectedBackgroundColor,
      imageSize: options.imageSize,
      buttonPadding: options.buttonPadding,
      textPadding: options.textPadding,
      localizedTextPadding: options.localizedTextPadding,
      localizedButtonPadding: options.localizedButtonPadding,
      backgroundBlurStyle: options.backgroundBlurStyle,
      direction: options.direction,
      borderRadiusMode: options.borderRadiusMode,
      backgroundBorderRadius: options.backgroundBorderRadius,
      itemBorderRadius: options.itemBorderRadius,
      backgroundSystemMaterial: options.backgroundSystemMaterial
    })
  }

  static capsule(options: CapsuleSegmentButtonConstructionOptions): SegmentButtonOptions {
    return new SegmentButtonOptions({
      type: 'capsule',
      buttons: options.buttons,
      multiply: options.multiply,
      fontColor: options.fontColor,
      selectedFontColor: options.selectedFontColor,
      fontSize: options.fontSize,
      selectedFontSize: options.selectedFontSize,
      fontWeight: options.fontWeight,
      selectedFontWeight: options.selectedFontWeight,
      backgroundColor: options.backgroundColor,
      selectedBackgroundColor: options.selectedBackgroundColor,
      imageSize: options.imageSize,
      buttonPadding: options.buttonPadding,
      textPadding: options.textPadding,
      localizedTextPadding: options.localizedTextPadding,
      localizedButtonPadding: options.localizedButtonPadding,
      backgroundBlurStyle: options.backgroundBlurStyle,
      direction: options.direction,
      borderRadiusMode: options.borderRadiusMode,
      backgroundBorderRadius: options.backgroundBorderRadius,
      itemBorderRadius: options.itemBorderRadius,
      backgroundSystemMaterial: options.backgroundSystemMaterial
    })
  }
}

@Component
struct MultiSelectBackground {
  @ObjectLink optionsArray: SegmentButtonItemOptionsArray
  @ObjectLink options: SegmentButtonOptions
  @Consume buttonBorderRadius: LocalizedBorderRadiuses[]

  build() {
    Row({ space: 1 }) {
      ForEach(this.optionsArray, (_: SegmentButtonItemOptions, index) => {
        if (index < MAX_ITEM_COUNT) {
          Stack()
            .direction(this.options.direction)
            .layoutWeight(1)
            .height('100%')
            .backgroundColor(this.options.backgroundColor ?? segmentButtonTheme.BACKGROUND_COLOR)
            .borderRadius(this.buttonBorderRadius[index])
            .backgroundBlurStyle(this.options.backgroundBlurStyle, undefined, { disableSystemAdaptation: true })
        }
      })
    }
    .direction(this.options.direction)
    .padding(this.options.componentPadding)
  }
}

@Component
struct SelectItem {
  @ObjectLink optionsArray: SegmentButtonItemOptionsArray
  @ObjectLink options: SegmentButtonOptions
  @Link selectedIndexes: number[]
  @Consume zoomScaleArray: number[]
  @Consume buttonBorderRadius: LocalizedBorderRadiuses[]
  @Prop isSegmentFocusStyleCustomized: boolean;
  @Consume openSelectedItemSystemMaterial?: boolean = false;
  @Consume selectedItemScale?: ScaleOptions;


  getBackgroundColor(): ResourceColor {
    if (this.options.selectedBackgroundColor) {
      return this.options.selectedBackgroundColor;
    }
    if (this.options.type === 'tab') {
      return segmentButtonTheme.TAB_SELECTED_BACKGROUND_COLOR;
    } else {
      return segmentButtonTheme.CAPSULE_SELECTED_BACKGROUND_COLOR;
    }
  }

  getScale(): ScaleOptions | undefined {
    if (this.openSelectedItemSystemMaterial) {
      return this.selectedItemScale;
    } else {
      return {
        x: this.zoomScaleArray[this.selectedIndexes[0]],
        y: this.zoomScaleArray[this.selectedIndexes[0]]
      };
    }
  }

  getOpacity() {
    if (this.openSelectedItemSystemMaterial) {
      return 0.7;
    } else {
      return 1;
    }
  }

  build() {
    if (this.selectedIndexes !== void 0 && this.selectedIndexes.length !== 0) {
      Stack()
        .direction(this.options.direction)
        .borderRadius(this.buttonBorderRadius[this.selectedIndexes[0]])
        .width('100%')
        .height('100%')
        .backgroundColor(this.getBackgroundColor())
        .scale(this.getScale())
        .opacity(this.getOpacity())
    }
  }
}

@Component
struct MultiSelectItemArray {
  @ObjectLink optionsArray: SegmentButtonItemOptionsArray
  @ObjectLink @Watch('onOptionsChange') options: SegmentButtonOptions
  @Link @Watch('onSelectedChange') selectedIndexes: number[]
  @Consume zoomScaleArray: number[]
  @Consume buttonBorderRadius: LocalizedBorderRadiuses[]
  @State multiColor: ResourceColor[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => Color.Transparent)

  onOptionsChange() {
    for (let i = 0; i < this.selectedIndexes.length; i++) {
      this.multiColor[this.selectedIndexes[i]] = this.options.selectedBackgroundColor ??
        segmentButtonTheme.CAPSULE_SELECTED_BACKGROUND_COLOR
    }
  }

  onSelectedChange() {
    for (let i = 0; i < MAX_ITEM_COUNT; i++) {
      this.multiColor[i] = Color.Transparent
    }
    for (let i = 0; i < this.selectedIndexes.length; i++) {
      this.multiColor[this.selectedIndexes[i]] = this.options.selectedBackgroundColor ??
        segmentButtonTheme.CAPSULE_SELECTED_BACKGROUND_COLOR
    }
  }

  aboutToAppear() {
    for (let i = 0; i < this.selectedIndexes.length; i++) {
      this.multiColor[this.selectedIndexes[i]] = this.options.selectedBackgroundColor ??
        segmentButtonTheme.CAPSULE_SELECTED_BACKGROUND_COLOR
    }
  }

  build() {
    Row({ space: 1 }) {
      ForEach(this.optionsArray, (_: SegmentButtonItemOptions, index) => {
        if (index < MAX_ITEM_COUNT) {
          Stack()
            .direction(this.options.direction)
            .layoutWeight(1)
            .height('100%')
            .backgroundColor(this.multiColor[index])
            .borderRadius(this.buttonBorderRadius[index])
        }
      })
    }
    .direction(this.options.direction)
    .padding(this.options.componentPadding)
  }
}

@Component
struct SegmentButtonItem {
  @Link selectedIndexes: number[]
  @Link @Watch('onFocusIndex') focusIndex: number;
  @Prop @Require maxFontScale: number | Resource
  @ObjectLink itemOptions: SegmentButtonItemOptions
  @ObjectLink options: SegmentButtonOptions;
  @ObjectLink property: ItemProperty
  @Prop index: number
  @State isTextSupportMarquee: boolean =
    resourceToNumber(this.getUIContext()?.getHostContext(), segmentButtonTheme.SEGMENT_ITEM_TEXT_OVERFLOW, 1.0) === 0.0;
  @Prop isMarqueeAndFadeout: boolean;
  @Prop isSegmentFocusStyleCustomized: boolean;
  @State isTextInMarqueeCondition: boolean = false;
  @State isButtonTextFadeout?: boolean = false;
  @Consume useAdaptiveLineHeight: boolean;
  private groupId: string = ''
  @Prop @Watch('onFocusIndex') hover: boolean;

  private getTextPadding(): Padding | Dimension | LocalizedPadding {
    if (this.options.localizedTextPadding) {
      return this.options.localizedTextPadding
    }
    if (this.options.textPadding !== void (0)) {
      return this.options.textPadding
    }
    return 0
  }

  private getButtonPadding(): Padding | Dimension | LocalizedPadding {
    if (this.options.localizedButtonPadding) {
      return this.options.localizedButtonPadding
    }
    if (this.options.buttonPadding !== void (0)) {
      return this.options.buttonPadding
    }
    if (this.options.type === 'capsule' && this.options.showText && this.options.showIcon) {
      return {
        top: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_CAPSULE_VERTICAL_PADDING),
        bottom: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_CAPSULE_VERTICAL_PADDING),
        start: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_HORIZONTAL_PADDING),
        end: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_HORIZONTAL_PADDING)
      }
    }
    return {
      top: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_VERTICAL_PADDING),
      bottom: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_VERTICAL_PADDING),
      start: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_HORIZONTAL_PADDING),
      end: LengthMetrics.resource(segmentButtonTheme.SEGMENT_TEXT_HORIZONTAL_PADDING)
    }
  }

  onFocusIndex(): void {
    this.isTextInMarqueeCondition =
      this.isSegmentFocusStyleCustomized && (this.focusIndex === this.index || this.hover);
  }

  aboutToAppear(): void {
    this.isButtonTextFadeout = this.isSegmentFocusStyleCustomized;
  }

  isDefaultSelectedFontColor(): boolean {
    if (this.options.type === 'tab') {
      return this.options.selectedFontColor === segmentButtonTheme.TAB_SELECTED_FONT_COLOR;
    } else if (this.options.type === 'capsule') {
      return this.options.selectedFontColor === segmentButtonTheme.CAPSULE_SELECTED_FONT_COLOR;
    }
    return false;
  }

  private getFontColor(): ResourceColor {
    if (this.property.isSelected) {
      if (this.isDefaultSelectedFontColor() && this.isSegmentFocusStyleCustomized && this.focusIndex === this.index) {
        return segmentButtonTheme.SEGMENT_BUTTON_FOCUS_TEXT_COLOR;
      }
      return this.options.selectedFontColor ?? segmentButtonTheme.CAPSULE_SELECTED_FONT_COLOR;
    }
    return this.options.fontColor ?? segmentButtonTheme.FONT_COLOR;
  }

  private getAccessibilityText(): Resource | undefined {
    if (this.selectedIndexes.includes(this.index) &&
      typeof this.itemOptions.selectedIconAccessibilityText !== undefined) {
      return this.itemOptions.selectedIconAccessibilityText as Resource
    } else if (!this.selectedIndexes.includes(this.index) &&
      typeof this.itemOptions.iconAccessibilityText !== undefined) {
      return this.itemOptions.iconAccessibilityText as Resource
    }
    return undefined;
  }

  build() {
    Column({ space: 2 }) {
      if (this.options.showIcon) {
        Image(this.property.isSelected ? this.itemOptions.selectedIcon : this.itemOptions.icon)
          .direction(this.options.direction)
          .size(this.options.imageSize ?? { width: 24, height: 24 })
          .draggable(false)
          .fillColor(this.getFontColor())
          .accessibilityText(this.getAccessibilityText())
      }
      if (this.options.showText) {
        Text(this.itemOptions.text)
          .direction(this.options.direction)
          .fontColor(this.getFontColor())
          .fontWeight(this.property.fontWeight)
          .fontSize(this.property.fontSize)
          .minFontSize(this.isSegmentFocusStyleCustomized ? this.property.fontSize : 9)
          .maxFontSize(this.property.fontSize)
          .maxFontScale(this.maxFontScale)
          .textOverflow({
            overflow: this.isTextSupportMarquee ? TextOverflow.MARQUEE : TextOverflow.Ellipsis
          })
          .marqueeOptions({
            start: this.isTextInMarqueeCondition,
            fadeout: this.isButtonTextFadeout,
            marqueeStartPolicy: MarqueeStartPolicy.DEFAULT
          })
          .maxLines(1)
          .textAlign(TextAlign.Center)
          .padding(this.getTextPadding())
          .includeFontPadding(this.useAdaptiveLineHeight)
          .fallbackLineSpacing(this.useAdaptiveLineHeight)
      }
    }
    .direction(this.options.direction)
    .justifyContent(FlexAlign.Center)
    .padding(this.getButtonPadding())
    .constraintSize({ minHeight: segmentButtonTheme.CONSTRAINT_SIZE_MIN_HEIGHT })
  }
}

@Observed
class HoverColorProperty {
  public hoverColor: ResourceColor = Color.Transparent
}

@Component
struct PressAndHoverEffect {
  @Consume buttonItemsSize: SizeOptions[]
  @Prop press: boolean
  @Prop hover: boolean
  @ObjectLink colorProperty: HoverColorProperty
  @Consume buttonBorderRadius: LocalizedBorderRadiuses[]
  @ObjectLink options: SegmentButtonOptions;
  pressIndex: number = 0
  pressColor: ResourceColor = segmentButtonTheme.PRESS_COLOR

  build() {
    Stack()
      .direction(this.options.direction)
      .size(this.buttonItemsSize[this.pressIndex])
      .backgroundColor(this.press && this.hover ? this.pressColor : this.colorProperty.hoverColor)
      .borderRadius(this.buttonBorderRadius[this.pressIndex])
  }
}

@Component
struct PressAndHoverEffectArray {
  @ObjectLink buttons: SegmentButtonItemOptionsArray
  @ObjectLink options: SegmentButtonOptions
  @Link pressArray: boolean[]
  @Link hoverArray: boolean[]
  @Link hoverColorArray: HoverColorProperty[]
  @Consume zoomScaleArray: number[]

  build() {
    Row({ space: 1 }) {
      ForEach(this.buttons, (item: SegmentButtonItemOptions, index) => {
        if (index < MAX_ITEM_COUNT) {
          Stack() {
            PressAndHoverEffect({
              pressIndex: index,
              colorProperty: this.hoverColorArray[index],
              press: this.pressArray[index],
              hover: this.hoverArray[index],
              options: this.options,
            })
          }
          .direction(this.options.direction)
          .scale({
            x: this.options.type === 'capsule' && (this.options.multiply ?? false) ? 1 : this.zoomScaleArray[index],
            y: this.options.type === 'capsule' && (this.options.multiply ?? false) ? 1 : this.zoomScaleArray[index]
          })
        }
      })
    }.direction(this.options.direction)
  }
}

@Component
struct SegmentButtonItemArrayComponent {
  @ObjectLink @Watch('onOptionsArrayChange') optionsArray: SegmentButtonItemOptionsArray
  @ObjectLink @Watch('onOptionsChange') options: SegmentButtonOptions
  @Link selectedIndexes: number[]
  @Link componentSize: SizeOptions
  @Consume buttonBorderRadius: LocalizedBorderRadiuses[]
  @Consume @Watch('onButtonItemsSizeChange') buttonItemsSize: SizeOptions[]
  @Consume positionTrigger: number
  @Consume @Watch('onFocusIndex') focusIndex: number;
  @Consume zoomScaleArray: number[]
  @Consume buttonItemProperty: ItemProperty[]
  @Consume buttonItemsSelected: boolean[]
  @Link pressArray: boolean[]
  @Link hoverArray: boolean[]
  @Link hoverColorArray: HoverColorProperty[]
  @Prop @Require maxFontScale: number | Resource
  @State buttonWidth: number[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => 0)
  @State buttonHeight: number[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => 0)
  @State isMarqueeAndFadeout: boolean = false;
  private buttonItemsRealHeight: number[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => 0)
  private groupId: string = util.generateRandomUUID(true)
  public onItemClicked?: Callback<number>
  @Prop isSegmentFocusStyleCustomized: boolean;

  onButtonItemsSizeChange() {
    this.buttonItemsSize.forEach((value, index) => {
      this.buttonWidth[index] = value.width as number
      this.buttonHeight[index] = value.height as number
    })
  }

  changeSelectedIndexes(buttonsLength: number) {
    if (this.optionsArray.changeStartIndex === void 0 || this.optionsArray.deleteCount === void 0 ||
      this.optionsArray.addLength === void 0) {
      return
    }
    if (!(this.options.multiply ?? false)) {
      // Single-select
      if (this.selectedIndexes[0] === void 0) {
        return
      }
      if (this.selectedIndexes[0] < this.optionsArray.changeStartIndex) {
        return
      }
      if (this.optionsArray.changeStartIndex + this.optionsArray.deleteCount > this.selectedIndexes[0]) {
        if (this.options.type === 'tab') {
          this.selectedIndexes[0] = 0
        } else if (this.options.type === 'capsule') {
          this.selectedIndexes = []
        }
      } else {
        this.selectedIndexes[0] = this.selectedIndexes[0] - this.optionsArray.deleteCount + this.optionsArray.addLength
      }
    } else {
      // Multi-select
      let saveIndexes = this.selectedIndexes
      for (let i = 0; i < this.optionsArray.deleteCount; i++) {
        let deleteIndex = saveIndexes.indexOf(this.optionsArray.changeStartIndex)
        let indexes = saveIndexes.map(value => this.optionsArray.changeStartIndex &&
          (value > this.optionsArray.changeStartIndex) ? value - 1 : value)
        if (deleteIndex !== -1) {
          indexes.splice(deleteIndex, 1)
        }
        saveIndexes = indexes
      }
      for (let i = 0; i < this.optionsArray.addLength; i++) {
        let indexes = saveIndexes.map(value => this.optionsArray.changeStartIndex &&
          (value >= this.optionsArray.changeStartIndex) ? value + 1 : value)
        saveIndexes = indexes
      }
      this.selectedIndexes = saveIndexes
    }

  }

  changeFocusIndex(buttonsLength: number) {
    if (this.optionsArray.changeStartIndex === void 0 || this.optionsArray.deleteCount === void 0 ||
      this.optionsArray.addLength === void 0) {
      return
    }
    if (this.focusIndex === -1) {
      return
    }
    if (this.focusIndex < this.optionsArray.changeStartIndex) {
      return
    }
    if (this.optionsArray.changeStartIndex + this.optionsArray.deleteCount > this.focusIndex) {
      this.focusIndex = 0
    } else {
      this.focusIndex = this.focusIndex - this.optionsArray.deleteCount + this.optionsArray.addLength
    }

  }

  onOptionsArrayChange() {
    if (this.options === void 0 || this.options.buttons === void 0) {
      return
    }
    let buttonsLength = Math.min(this.options.buttons.length, this.buttonItemsSize.length)
    if (this.optionsArray.changeStartIndex !== void 0 && this.optionsArray.deleteCount !== void 0 &&
      this.optionsArray.addLength !== void 0) {
      this.changeSelectedIndexes(buttonsLength)
      this.changeFocusIndex(buttonsLength)
      this.optionsArray.changeStartIndex = void 0
      this.optionsArray.deleteCount = void 0
      this.optionsArray.addLength = void 0
    }
  }

  onOptionsChange() {
    if (this.options === void 0 || this.options.buttons === void 0) {
      return
    }
    this.calculateBorderRadius()
  }

  onFocusIndex(): void {
    this.isMarqueeAndFadeout = this.isSegmentFocusStyleCustomized && !this.isMarqueeAndFadeout;
  }

  aboutToAppear() {
    for (let index = 0; index < this.buttonItemsRealHeight.length; index++) {
      this.buttonItemsRealHeight[index] = 0
    }
  }

  private getFocusItemBorderRadius(index: number): LocalizedBorderRadiuses {
    if (index < 0 || index >= this.buttonBorderRadius.length) {
      return {
        topStart: LengthMetrics.vp(0),
        topEnd: LengthMetrics.vp(0),
        bottomStart: LengthMetrics.vp(0),
        bottomEnd: LengthMetrics.vp(0)
      };
    }

    let focusOffset = 0;
    if (this.options.type === 'capsule' &&
      this.focusIndex >= 0 &&
      this.focusIndex < this.buttonItemsSelected.length &&
      this.buttonItemsSelected[this.focusIndex]) {
      focusOffset = CAPSULE_FOCUS_SELECTED_OFFSET;
    }

    let borderRadius: LocalizedBorderRadiuses = this.buttonBorderRadius[index];

    return {
      topStart: LengthMetrics.vp((borderRadius.topStart?.value ?? 0) + focusOffset),
      topEnd: LengthMetrics.vp((borderRadius.topEnd?.value ?? 0) + focusOffset),
      bottomStart: LengthMetrics.vp((borderRadius.bottomStart?.value ?? 0) + focusOffset),
      bottomEnd: LengthMetrics.vp((borderRadius.bottomEnd?.value ?? 0) + focusOffset)
    };
  }

  private getFocusStackSize(index: number): SizeOptions {
    const isCapsuleAndSelected = this.options.type === 'capsule' &&
      this.focusIndex >= 0 &&
      this.focusIndex < this.buttonItemsSelected.length &&
      this.buttonItemsSelected[this.focusIndex];

    return {
      width: isCapsuleAndSelected
        ? this.buttonWidth[index] + CAPSULE_FOCUS_SELECTED_OFFSET * 2
        : this.buttonWidth[index],
      height: isCapsuleAndSelected
        ? this.buttonHeight[index] + CAPSULE_FOCUS_SELECTED_OFFSET * 2
        : this.buttonHeight[index]
    };
  }

  @Builder
  focusStack(index: number) {
    Stack() {
      Stack()
        .direction(this.options.direction)
        .borderRadius(this.getFocusItemBorderRadius(index))
        .size(this.getFocusStackSize(index))
        .borderColor(segmentButtonTheme.FOCUS_BORDER_COLOR)
        .borderWidth(2)
    }
    .direction(this.options.direction)
    .size({ width: 1, height: 1 })
    .align(Alignment.Center)
    // Currently, isSegmentFocusStyleCustomized is set to true only on TV.
    // Since the TV requires the use of the built-in focus style, the custom focus style is hidden.
    .visibility(!this.isSegmentFocusStyleCustomized && this.focusIndex === index ? Visibility.Visible : Visibility.None)
  }

  calculateBorderRadius() {
    // Calculate the border radius for each button
    let borderRadiusArray: LocalizedBorderRadiuses[] = Array.from({
      length: MAX_ITEM_COUNT
    }, (_: Object): LocalizedBorderRadiuses => {
      return {
        topStart: LengthMetrics.vp(0),
        topEnd: LengthMetrics.vp(0),
        bottomStart: LengthMetrics.vp(0),
        bottomEnd: LengthMetrics.vp(0)
      }
    });

    const isSingleSelect = this.options.type === 'tab' || !(this.options.multiply ?? false);
    const buttonsLength =
      this.options.buttons ? Math.min(this.options.buttons.length, this.buttonItemsSize.length) : MIN_ITEM_COUNT;

    const setAllCorners = (array: LocalizedBorderRadiuses[], index: number, lengthMetrics: LengthMetrics) => {
      if (!array || index < 0 || index >= array.length) {
        return;
      }

      const safeLengthMetrics = lengthMetrics.value < 0 ? LengthMetrics.vp(0) : lengthMetrics;
      array[index].topStart = safeLengthMetrics;
      array[index].topEnd = safeLengthMetrics;
      array[index].bottomStart = safeLengthMetrics;
      array[index].bottomEnd = safeLengthMetrics;
    };

    const setLeftCorners = (array: LocalizedBorderRadiuses[], index: number, lengthMetrics: LengthMetrics) => {
      if (!array || index < 0 || index >= array.length) {
        return;
      }
      const safeLengthMetrics = lengthMetrics.value < 0 ? LengthMetrics.vp(0) : lengthMetrics;
      const zeroLengthMetrics = LengthMetrics.vp(0);
      array[index].topStart = safeLengthMetrics;
      array[index].topEnd = zeroLengthMetrics;
      array[index].bottomStart = safeLengthMetrics;
      array[index].bottomEnd = zeroLengthMetrics;
    };

    const setRightCorners = (array: LocalizedBorderRadiuses[], index: number, lengthMetrics: LengthMetrics) => {
      if (!array || index < 0 || index >= array.length) {
        return;
      }
      const safeLengthMetrics = lengthMetrics.value < 0 ? LengthMetrics.vp(0) : lengthMetrics;
      const zeroLengthMetrics = LengthMetrics.vp(0);
      array[index].topStart = zeroLengthMetrics;
      array[index].topEnd = safeLengthMetrics;
      array[index].bottomStart = zeroLengthMetrics;
      array[index].bottomEnd = safeLengthMetrics;
    };

    const setMiddleCorners = (array: LocalizedBorderRadiuses[], index: number) => {
      if (!array || index < 0 || index >= array.length) {
        return;
      }
      array[index].topStart = LengthMetrics.vp(0);
      array[index].topEnd = LengthMetrics.vp(0);
      array[index].bottomStart = LengthMetrics.vp(0);
      array[index].bottomEnd = LengthMetrics.vp(0);
    };

    for (let index = 0; index < this.buttonBorderRadius.length; index++) {
      let halfButtonItemsSizeHeight = this.buttonItemsSize[index].height as number / 2;
      let radius = this.options.iconTextRadius ?? halfButtonItemsSizeHeight; // default radius
      // Determine which border radius to use based on mode setting
      const isCustomMode = this.options.borderRadiusMode === BorderRadiusMode.CUSTOM &&
        this.options.itemBorderRadius !== undefined;

      let radiusLengthMetrics: LengthMetrics;
      if (isCustomMode && this.options.itemBorderRadius) {
        // Use custom border radius from options
        radiusLengthMetrics = this.options.itemBorderRadius;
      } else {
        // Use default calculated radius value
        radiusLengthMetrics = LengthMetrics.vp(radius);
      }
      if (isSingleSelect) {
        // single-select
        setAllCorners(borderRadiusArray, index, radiusLengthMetrics);
      } else {
        // multi-select
        if (index === 0) {
          setLeftCorners(borderRadiusArray, index, radiusLengthMetrics);
        } else if (index === buttonsLength - 1) {
          setRightCorners(borderRadiusArray, index, radiusLengthMetrics);
        } else {
          setMiddleCorners(borderRadiusArray, index);
        }
      }
    }

    this.buttonBorderRadius = borderRadiusArray;
  }

  getAccessibilityDescription(value?: ResourceStr, index?: number): string | undefined {
    if (value !== undefined) {
      return value as string;
    }
    const isSingleSelect = this.options.type === 'tab' || !this.options.multiply;

    if (isSingleSelect && index !== undefined && this.selectedIndexes.includes(index)) {
      return ACCESSIBILITY_SELECTED_DESCRIPTION;
    }

    return ACCESSIBILITY_DEFAULT_DESCRIPTION;
  }

  isDefaultSelectedBgColor(): boolean {
    if (this.options.type === 'tab') {
      return this.options.selectedBackgroundColor === segmentButtonTheme.TAB_SELECTED_BACKGROUND_COLOR;
    } else if (this.options.type === 'capsule') {
      return this.options.selectedBackgroundColor === segmentButtonTheme.CAPSULE_SELECTED_BACKGROUND_COLOR;
    }
    return true;
  }

  build() {
    if (this.optionsArray !== void 0 && this.optionsArray.length > 1) {
      Row({ space: 1 }) {
        ForEach(this.optionsArray, (item: SegmentButtonItemOptions, index) => {
          if (index < MAX_ITEM_COUNT) {
            Button() {
              SegmentButtonItem({
                isMarqueeAndFadeout: this.isMarqueeAndFadeout,
                isSegmentFocusStyleCustomized: this.isSegmentFocusStyleCustomized,
                selectedIndexes: $selectedIndexes,
                focusIndex: this.focusIndex,
                index: index,
                itemOptions: item,
                options: this.options,
                property: this.buttonItemProperty[index],
                groupId: this.groupId,
                maxFontScale: this.maxFontScale,
                hover: this.hoverArray[index],
              })
                .onSizeChange((_, newValue) => {
                  // Calculate height of items
                  this.buttonItemsRealHeight[index] = newValue.height as number
                  let maxHeight = Math.max(...this.buttonItemsRealHeight.slice(0, this.options.buttons ?
                    this.options.buttons.length : 0))
                  for (let index = 0; index < this.buttonItemsSize.length; index++) {
                    this.buttonItemsSize[index] = { width: this.buttonItemsSize[index].width, height: maxHeight }
                  }
                  this.calculateBorderRadius()
                })
            }
            .focusScopePriority(this.groupId,
              Math.min(...this.selectedIndexes) === index ? FocusPriority.PREVIOUS : FocusPriority.AUTO)
            .type(ButtonType.Normal)
            .stateEffect(false)
            .hoverEffect(HoverEffect.None)
            .backgroundColor(Color.Transparent)
            .accessibilityLevel(item.accessibilityLevel)
            .accessibilitySelected(this.options.multiply ? undefined : this.selectedIndexes.includes(index))
            .accessibilityChecked(this.options.multiply ? this.selectedIndexes.includes(index) : undefined)
            .accessibilityDescription(this.getAccessibilityDescription(item.accessibilityDescription, index))
            .direction(this.options.direction)
            .borderRadius(this.buttonBorderRadius[index])
            .scale({
              x: this.options.type === 'capsule' && (this.options.multiply ?? false) ? 1 : this.zoomScaleArray[index],
              y: this.options.type === 'capsule' && (this.options.multiply ?? false) ? 1 : this.zoomScaleArray[index]
            })
            .layoutWeight(1)
            .padding(0)
            .onSizeChange((_, newValue) => {
              this.buttonItemsSize[index] = { width: newValue.width, height: this.buttonItemsSize[index].height }
              //measure position
              if (newValue.width) {
                this.positionTrigger = (this.positionTrigger + 1) & 0xFFFFF // mod 2^20
              }
            })
            .overlay(this.focusStack(index), { align: Alignment.Center })
            .attributeModifier(this.isSegmentFocusStyleCustomized ? undefined :
              new FocusStyleButtonModifier((isFocused: boolean): void => {
                if (!isFocused && this.focusIndex === index) {
                  this.focusIndex = -1;
                  return;
                }
                if (isFocused) {
                  this.focusIndex = index;
                }
              }))
            .onFocus(() => {
              this.focusIndex = index;
              if (this.isSegmentFocusStyleCustomized) {
                this.customizeSegmentFocusStyle(index);
              }
            })
            .onBlur(() => {
              if (this.focusIndex === index) {
                this.focusIndex = -1;
              }
              this.hoverColorArray[index].hoverColor = Color.Transparent;
            })
            .gesture(TapGesture().onAction(() => {
              if (this.onItemClicked) {
                this.onItemClicked(index)
              }
              if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
                if (this.selectedIndexes.indexOf(index) === -1) {
                  this.selectedIndexes.push(index)
                } else {
                  this.selectedIndexes.splice(this.selectedIndexes.indexOf(index), 1)
                }
              } else {
                this.selectedIndexes[0] = index
              }
            }))
            .onTouch((event: TouchEvent) => {
              if (this.isSegmentFocusStyleCustomized) {
                this.getUIContext().getFocusController().clearFocus();
              }
              if (event.source !== SourceType.TouchScreen) {
                return
              }
              if (event.type === TouchType.Down) {
                animateTo({ curve: curves.interpolatingSpring(10, 1, 410, 38) }, () => {
                  this.zoomScaleArray[index] = 0.95
                })
              } else if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
                animateTo({ curve: curves.interpolatingSpring(10, 1, 410, 38) }, () => {
                  this.zoomScaleArray[index] = 1
                })
              }
            })
            .onHover((isHover: boolean) => {
              this.hoverArray[index] = isHover
              if (isHover) {
                animateTo({ duration: 250, curve: Curve.Friction }, () => {
                  this.hoverColorArray[index].hoverColor =
                    this.isSegmentFocusStyleCustomized && this.focusIndex === index ?
                      segmentButtonTheme.SEGMENT_BUTTON_FOCUS_CUSTOMIZED_BG_COLOR : segmentButtonTheme.HOVER_COLOR;
                })
              } else {
                animateTo({ duration: 250, curve: Curve.Friction }, () => {
                  this.hoverColorArray[index].hoverColor =
                    this.isSegmentFocusStyleCustomized && this.focusIndex === index ?
                      segmentButtonTheme.SEGMENT_BUTTON_FOCUS_CUSTOMIZED_BG_COLOR : Color.Transparent;
                })
              }
            })
            .onMouse((event: MouseEvent) => {
              switch (event.action) {
                case MouseAction.Press:
                  animateTo({ curve: curves.springMotion(0.347, 0.99) }, () => {
                    this.zoomScaleArray[index] = 0.95
                  })
                  animateTo({ duration: 100, curve: Curve.Sharp }, () => {
                    this.pressArray[index] = true
                  })
                  break;
                case MouseAction.Release:
                  animateTo({ curve: curves.springMotion(0.347, 0.99) }, () => {
                    this.zoomScaleArray[index] = 1
                  })
                  animateTo({ duration: 100, curve: Curve.Sharp }, () => {
                    this.pressArray[index] = false
                  })
                  break;
              }
            })
          }
        })
      }
      .direction(this.options.direction)
      .focusScopeId(this.groupId, true)
      .padding(this.options.componentPadding)
      .onSizeChange((_, newValue) => {
        this.componentSize = { width: newValue.width, height: newValue.height }
      })
    }
  }

  /**
   * 设置segmentbutton获焦时的样式
   * @param index
   */
  private customizeSegmentFocusStyle(index: number) {
    if (this.selectedIndexes !== void 0 && this.selectedIndexes.length !== 0 &&
      this.selectedIndexes[0] === index) { // 选中态
      this.hoverColorArray[index].hoverColor = this.isDefaultSelectedBgColor() ?
        segmentButtonTheme.SEGMENT_BUTTON_FOCUS_CUSTOMIZED_BG_COLOR : this.options.selectedBackgroundColor;
    } else { // 未选中态
      this.hoverColorArray[index].hoverColor = this.options.backgroundColor === segmentButtonTheme.BACKGROUND_COLOR ?
        segmentButtonTheme.SEGMENT_BUTTON_FOCUS_CUSTOMIZED_BG_COLOR : this.options.backgroundColor;
    }
  }
}

@Observed
class ItemProperty {
  public fontColor: ResourceColor = segmentButtonTheme.FONT_COLOR
  public fontSize: DimensionNoPercentage = segmentButtonTheme.FONT_SIZE
  public fontWeight: FontWeight = FontWeight.Regular
  public isSelected: boolean = false
}

@Component
export struct SegmentButton {
  @Prop enableStateAnimation: boolean = false
  @ObjectLink @Watch('onOptionsChange') options: SegmentButtonOptions
  @Link @Watch('onSelectedChange') selectedIndexes: number[]
  public onItemClicked?: Callback<number>
  @Prop maxFontScale: number | Resource = DEFAULT_MAX_FONT_SCALE
  @State componentSize: SizeOptions = { width: 0, height: 0 }
  @Provide buttonBorderRadius: LocalizedBorderRadiuses[] = Array.from({
    length: MAX_ITEM_COUNT
  }, (_: Object, index): LocalizedBorderRadiuses => {
    return {
      topStart: LengthMetrics.vp(0),
      topEnd: LengthMetrics.vp(0),
      bottomStart: LengthMetrics.vp(0),
      bottomEnd: LengthMetrics.vp(0)
    }
  })
  @Provide buttonItemsSize: SizeOptions[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index): SizeOptions => {
    return {}
  })
  @Provide @Watch('onItemsPositionChange') positionTrigger: number = 0
  @Provide buttonItemsSelected: boolean[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => false)
  @Provide buttonItemProperty: ItemProperty[] = Array.from({
    length: MAX_ITEM_COUNT
  }, (_: Object, index) => new ItemProperty())
  @Provide focusIndex: number = -1
  @State selectedItemOffsetX: number = 0
  @Provide zoomScaleArray: number[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => 1.0)
  @State pressArray: boolean[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => false)
  @State hoverArray: boolean[] = Array.from({ length: MAX_ITEM_COUNT }, (_: Object, index) => false)
  @State hoverColorArray: HoverColorProperty[] = Array.from({
    length: MAX_ITEM_COUNT
  }, (_: Object, index) => new HoverColorProperty())
  private doSelectedChangeAnimate: boolean = false
  private isCurrentPositionSelected: boolean = false
  private isCurrentPositionPressed: boolean = false
  private panGestureStartPoint: Point = { x: 0, y: 0 }
  private isPanGestureMoved: boolean = false
  @State shouldMirror: boolean = false
  private isGestureInProgress: boolean = false;
  private isCustomizedCache?: boolean;
  @Provide openSelectedItemSystemMaterial?: boolean = false;
  @Provide selectedItemScale?: ScaleOptions = undefined;
  @Provide useAdaptiveLineHeight: boolean = false;
  private environmentCallbackID?: number = undefined;
  private environmentCallback: EnvironmentCallback = {
    onConfigurationUpdated: (configuration) => {
      this.updateLanguageLineHeight();
      this.layoutAlgorithm.shouldMirror = this.isShouldMirror()
    },
    onMemoryLevel() {
    }
  };

  private layoutAlgorithm: SegmentButtonLayoutAlgorithm = new SegmentButtonLayoutAlgorithm()

  onItemsPositionChange() {
    if (this.options === void 0 || this.options.buttons === void 0) {
      return
    }
    if (this.options.type === 'capsule') {
      this.options.onButtonsUpdated();
    }
    if (this.doSelectedChangeAnimate) {
      this.updateAnimatedProperty(this.getSelectedChangeCurve())
    } else {
      this.updateAnimatedProperty(null)
    }
  }

  setItemsSelected() {
    this.buttonItemsSelected.forEach((_, index) => {
      this.buttonItemsSelected[index] = false
    })
    if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
      this.selectedIndexes.forEach(index => this.buttonItemsSelected[index] = true)
    } else {
      this.buttonItemsSelected[this.selectedIndexes[0]] = true
    }
  }

  updateSelectedIndexes() {
    if (this.selectedIndexes === void 0) {
      this.selectedIndexes = []
    }
    if (this.options.type === 'tab' && this.selectedIndexes.length === 0) {
      this.selectedIndexes[0] = 0
    }
    if (this.selectedIndexes.length > 1) {
      if (this.options.type === 'tab') {
        this.selectedIndexes = [0]
      }
      if (this.options.type === 'capsule' && !(this.options.multiply ?? false)) {
        this.selectedIndexes = []
      }
    }
    let invalid = this.selectedIndexes.some(index => {
      return (index === void 0 || index < 0 || (this.options.buttons && index >= this.options.buttons.length))
    })
    if (invalid) {
      if (this.options.type === 'tab') {
        this.selectedIndexes = [0]
      } else {
        this.selectedIndexes = []
      }
    }
  }

  onOptionsChange() {
    if (this.options === void 0 || this.options.buttons === void 0) {
      return
    }
    this.shouldMirror = this.isShouldMirror()
    this.updateSelectedIndexes()
    this.setItemsSelected()
    this.layoutAlgorithm.componentPadding = this.getUIContext().vp2px(
      Number.parseFloat(this.options.componentPadding.toString())
    )
    this.layoutAlgorithm.rowSpace = this.getUIContext().vp2px(1)
    this.layoutAlgorithm.selectedIndex = this.selectedIndexes.length > 0 ? this.selectedIndexes[0] : -1
    this.layoutAlgorithm.multiply = this.options.type === 'capsule' && (this.options.multiply ?? false)
    this.layoutAlgorithm.shouldMirror = this.shouldMirror
    this.updateAnimatedProperty(null)
    if (this.environmentCallbackID === undefined && deviceInfo.sdkApiVersion >= 26) {
      let abilityContext = this.getUIContext().getHostContext()
      if (abilityContext) {
        this.environmentCallbackID = abilityContext.getApplicationContext().on('environment', this.environmentCallback)
      }
    }
  }

  onSelectedChange() {
    if (this.options === void 0 || this.options.buttons === void 0) {
      return
    }
    this.updateSelectedIndexes()
    this.setItemsSelected()

    const oldIndex = this.layoutAlgorithm.selectedIndex
    const newIndex = this.selectedIndexes.length > 0 ? this.selectedIndexes[0] : -1
    if (oldIndex >= 0 && newIndex >= 0 && oldIndex !== newIndex &&
      this.layoutAlgorithm.buttonWidth > 0) {
      const deltaX = this.layoutAlgorithm.getButtonX(oldIndex) - this.layoutAlgorithm.getButtonX(newIndex)
      this.selectedItemOffsetX = this.getUIContext().px2vp(deltaX)
    }

    this.layoutAlgorithm.selectedIndex = newIndex
    if (this.doSelectedChangeAnimate  || this.enableStateAnimation) {
      this.updateAnimatedProperty(this.getSelectedChangeCurve())
    } else {
      this.updateAnimatedProperty(null)
    }
  }

  aboutToAppear() {
    if (this.options === void 0 || this.options.buttons === void 0) {
      return
    }
    this.options.onButtonsChange = () => {
      if (this.options.type === 'tab') {
        this.selectedIndexes = [0]
      } else {
        this.selectedIndexes = []
      }
    }
    this.shouldMirror = this.isShouldMirror()
    this.updateSelectedIndexes()
    this.setItemsSelected()
    this.updateAnimatedProperty(null)
    if (deviceInfo.sdkApiVersion >= 26) {
      this.updateLanguageLineHeight();
      let abilityContext = this.getUIContext().getHostContext();
      if (abilityContext) {
        this.environmentCallbackID = abilityContext.getApplicationContext().on('environment', this.environmentCallback);
      }
    }
  }

  aboutToDisappear(): void {
    if (deviceInfo.sdkApiVersion >= 26 && this.environmentCallbackID) {
      let abilityContext = this.getUIContext().getHostContext();
      if (abilityContext) {
        abilityContext.getApplicationContext().off('environment', this.environmentCallbackID);
      }
      this.environmentCallbackID = void 0;
    }
  }

  updateLanguageLineHeight(): void {
    const resourceManager = this.getUIContext().getHostContext()?.resourceManager;
    if (!resourceManager) {
      console.error(`[SegmentButton] failed to get resourceManager`);
      return;
    }
    try {
      this.useAdaptiveLineHeight = resourceManager!.getStringByNameSync('text_fallback_line_spacing') === 'true';
    } catch (e) {
      console.error(`[SegmentButton] failed to get text_fallback_line_spacing resource`);
    }
  }

  private isMouseWheelScroll(event: GestureEvent) {
    return event.source === SourceType.Mouse && !this.isPanGestureMoved
  }

  private isMovedFromPanGestureStartPoint(x: number, y: number) {
    return !nearEqual(x, this.panGestureStartPoint.x) || !nearEqual(y, this.panGestureStartPoint.y)
  }

  private isShouldMirror(): boolean {
    if (this.options.direction === Direction.Rtl) {
      return true
    } else if (this.options.direction === Direction.Ltr) {
      return false
    }
    // 获取系统语言
    try {
      let appPreferredLanguage: string = I18n.System.getAppPreferredLanguage();
      if (I18n.isRTL(appPreferredLanguage)) {
        return true;
      }
    } catch (error) {
      console.error(`Ace SegmentButton getSystemLanguage, error: ${error.toString()}`);
    }
    return false;
  }

  private isMultiplyCapsule(): boolean {
    return this.options !== undefined &&
      this.options.type === 'capsule' && (this.options.multiply ?? false);
  }

  private shouldShowBackground(): boolean {
    return !this.isMultiplyCapsule() && this.isBackgroundSystemMaterialEnabled();
  }

  private getButtonBackgroundColor(): ResourceColor | undefined {
    if (!this.shouldShowBackground()) {
      return undefined;
    }
    return this.options.backgroundColor ?? segmentButtonTheme.BACKGROUND_COLOR;
  }

  private getButtonBorderRadius(): Length | undefined {
    if (!this.shouldShowBackground()) {
      return undefined;
    }
    return getBackgroundBorderRadius(this.options, this.componentSize.height as number / 2);
  }

  private getButtonSystemMaterial(): uiMaterial.Material | undefined {
    if (!this.shouldShowBackground()) {
      return undefined;
    }
    return this.options.backgroundSystemMaterial;
  }

  private isSegmentFocusStyleCustomized(): boolean {
    if (this.isCustomizedCache === undefined) {
      this.isCustomizedCache = resourceToNumber(
        this.getUIContext()?.getHostContext(),
        segmentButtonTheme.SEGMENT_FOCUS_STYLE_CUSTOMIZED,
        1.0
      ) < 0.1; //PC platform returns 0.0, default returns 1.0, using <0.1 to differentiate platform styles.
    }
    return this.isCustomizedCache;
  }

  build() {
    Stack() {
      if (this.options !== void 0 && this.options.buttons != void 0) {
        DynamicLayout(this.layoutAlgorithm) {
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            MultiSelectBackground({
              optionsArray: this.options.buttons,
              options: this.options,
            })
          } else {
            Stack() {
              if (this.options.buttons !== void 0 && this.options.buttons.length > 1) {
                PressAndHoverEffectArray({
                  options: this.options,
                  buttons: this.options.buttons,
                  pressArray: this.pressArray,
                  hoverArray: this.hoverArray,
                  hoverColorArray: this.hoverColorArray
                })
              }
            }
            .direction(this.options.direction)
            .backgroundColor(this.options.backgroundColor ?? segmentButtonTheme.BACKGROUND_COLOR)
            .borderRadius(getBackgroundBorderRadius(
              this.options,
              this.componentSize.height as number / 2
            ))
            .backgroundBlurStyle(this.options.backgroundBlurStyle, undefined, { disableSystemAdaptation: true })
            .borderWidth(this.options.backgroundSystemMaterial ? undefined
              : segmentButtonTheme.SEGMENT_BUTTON_BORDER_WIDTH)
            .borderColor(this.options.backgroundSystemMaterial ? undefined
              : segmentButtonTheme.SEGMENT_BUTTON_BORDER_COLOR)
            .systemMaterial(this.options.backgroundSystemMaterial)
          }
          Stack() {
            if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
              MultiSelectItemArray({
                optionsArray: this.options.buttons,
                options: this.options,
                selectedIndexes: $selectedIndexes
              })
            } else {
              SelectItem({
                optionsArray: this.options.buttons,
                options: this.options,
                selectedIndexes: $selectedIndexes,
                isSegmentFocusStyleCustomized: this.isSegmentFocusStyleCustomized()
              })
            }
          }
          .direction(this.options.direction)
          .animation({ duration: 0 })
          .borderRadius(getBackgroundBorderRadius(
            this.options,
            this.componentSize.height as number / 2
          ))
          .translate({ x: this.selectedItemOffsetX })

          SegmentButtonItemArrayComponent({
            componentSize: $componentSize,
            pressArray: this.pressArray,
            hoverArray: this.hoverArray,
            hoverColorArray: this.hoverColorArray,
            optionsArray: this.options.buttons,
            options: this.options,
            selectedIndexes: $selectedIndexes,
            maxFontScale: this.getMaxFontSize(),
            onItemClicked: this.onItemClicked,
            isSegmentFocusStyleCustomized: this.isSegmentFocusStyleCustomized()
          })
        }
      }
    }
    .direction(this.options ? this.options.direction : undefined)
    .backgroundColor(this.getButtonBackgroundColor())
    .borderRadius(this.getButtonBorderRadius())
    .clip(false)
    .systemMaterial(this.getButtonSystemMaterial())
    .onBlur(() => {
      this.focusIndex = -1
    })
    .onKeyEvent((event: KeyEvent) => {
      if (this.options === void 0 || this.options.buttons === void 0) {
        return
      }
      if (event.type === KeyType.Down) {
        if (event.keyCode === KeyCode.KEYCODE_SPACE || event.keyCode === KeyCode.KEYCODE_ENTER ||
          event.keyCode === KeyCode.KEYCODE_NUMPAD_ENTER) {
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            if (this.selectedIndexes.indexOf(this.focusIndex) === -1) {
              // Select
              this.selectedIndexes.push(this.focusIndex)
            } else {
              // Unselect
              this.selectedIndexes.splice(this.selectedIndexes.indexOf(this.focusIndex), 1)
            }
          } else {
            // Pressed
            this.selectedIndexes[0] = this.focusIndex
          }
        }
      }
    })
    .accessibilityLevel('no')
    .priorityGesture(GestureGroup(GestureMode.Parallel,
      TapGesture()
        .onAction((event: GestureEvent) => {
          if (this.isGestureInProgress) {
            return;
          }
          let fingerInfo = event.fingerList.find(Boolean)
          if (fingerInfo === void 0) {
            return
          }
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          let selectedInfo = fingerInfo.localX

          let buttonLength: number = Math.min(this.options.buttons.length, this.buttonItemsSize.length)
          for (let i = 0; i < buttonLength; i++) {
            selectedInfo = selectedInfo - (this.buttonItemsSize[i].width as number)
            if (selectedInfo >= 0) {
              continue
            }
            this.doSelectedChangeAnimate =
              this.selectedIndexes[0] > Math.min(this.options.buttons.length,
                this.buttonItemsSize.length) ? false : true

            let realClickIndex: number = this.isShouldMirror() ? buttonLength - 1 - i : i
            if (this.onItemClicked) {
              this.onItemClicked(realClickIndex)
            }
            if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
              let selectedIndex: number = this.selectedIndexes.indexOf(realClickIndex)
              if (selectedIndex === -1) {
                this.selectedIndexes.push(realClickIndex)
              } else {
                this.selectedIndexes.splice(selectedIndex, 1)
              }
            } else {
              this.selectedIndexes[0] = realClickIndex
            }
            this.doSelectedChangeAnimate = false
            break
          }
        }),
      SwipeGesture()
        .onAction((event: GestureEvent) => {
          if (this.options === void 0 || this.options.buttons === void 0 ||
            event.sourceTool === SourceTool.TOUCHPAD) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            // Non swipe gesture in multi-select mode
            return
          }
          if (this.isCurrentPositionSelected) {
            return
          }

          // Only handle horizontal swipes (angle between -45 to 45 degrees or 135 to 225 degrees)
          let isHorizontalSwipe = (Math.abs(event.angle) <= 45) || (Math.abs(event.angle) >= 135);
          if (!isHorizontalSwipe) {
            return;
          }

          let isSwipeRight = Math.abs(event.angle) <= 45; // swipe right
          let isSwipeLeft = Math.abs(event.angle) >= 135; // swipe left

          let isSwipeToNext = this.isShouldMirror() ? isSwipeLeft : isSwipeRight;
          let isSwipeToPrevious = this.isShouldMirror() ? isSwipeRight : isSwipeLeft;

          if (isSwipeToNext && this.selectedIndexes[0] !== Math.min(this.options.buttons.length,
            this.buttonItemsSize.length) - 1) {
            // Move to next
            this.doSelectedChangeAnimate = true
            this.selectedIndexes[0] = this.selectedIndexes[0] + 1
            this.doSelectedChangeAnimate = false
          } else if (isSwipeToPrevious && this.selectedIndexes[0] !== 0) {
            // Move to previous
            this.doSelectedChangeAnimate = true
            this.selectedIndexes[0] = this.selectedIndexes[0] - 1
            this.doSelectedChangeAnimate = false
          }
        }),
      LongPressGesture({ repeat: false, duration: 200 })
        .onAction((event: GestureEvent) => {
          if (!this.isBackgroundSystemMaterialEnabled()) {
            return
          }
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            // Non long press gesture in multi-select mode
            return
          }
          let fingerInfo = event.fingerList.find(Boolean)
          if (fingerInfo === void 0) {
            return
          }
          let selectedInfo = fingerInfo.localX

          let buttonLength: number = Math.min(this.options.buttons.length, this.buttonItemsSize.length);
          for (let i = 0; i < buttonLength; i++) {
            selectedInfo = selectedInfo - (this.buttonItemsSize[i].width as number)
            if (selectedInfo < 0) {
              let realIndex = this.isShouldMirror() ? buttonLength - 1 - i : i;
              this.isCurrentPositionPressed = realIndex === this.selectedIndexes[0] ? true : false;
              break
            }
          }
          if (this.isCurrentPositionPressed && !this.openSelectedItemSystemMaterial) {
            this.startSelectMaterialAnimation();
          }
        })
        .onActionCancel((event: GestureEvent) => {
          if (!this.isBackgroundSystemMaterialEnabled()) {
            return
          }
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            // Non drag gesture in multi-select mode
            return
          }

          if (this.isCurrentPositionPressed && this.openSelectedItemSystemMaterial) {
            this.finishSelectMaterialAnimation();
          }
          this.isCurrentPositionPressed = false;
        })
        .onActionEnd((event: GestureEvent) => {
          if (!this.isBackgroundSystemMaterialEnabled()) {
            return
          }
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            // Non drag gesture in multi-select mode
            return
          }
          if (this.isCurrentPositionPressed && this.openSelectedItemSystemMaterial) {
            this.finishSelectMaterialAnimation();
          }
          this.isCurrentPositionPressed = false;
        }),
      PanGesture({ direction: PanDirection.Horizontal })
        .onActionStart((event: GestureEvent) => {
          this.isGestureInProgress = true;
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            // Non drag gesture in multi-select mode
            return
          }
          let fingerInfo = event.fingerList.find(Boolean)
          if (fingerInfo === void 0) {
            return
          }
          let selectedInfo = fingerInfo.localX
          this.panGestureStartPoint = { x: fingerInfo.globalX, y: fingerInfo.globalY }
          this.isPanGestureMoved = false

          let buttonLength: number = Math.min(this.options.buttons.length, this.buttonItemsSize.length);
          for (let i = 0; i < buttonLength; i++) {
            selectedInfo = selectedInfo - (this.buttonItemsSize[i].width as number)
            if (selectedInfo < 0) {
              let realIndex = this.isShouldMirror() ? buttonLength - 1 - i : i;
              this.isCurrentPositionSelected = realIndex === this.selectedIndexes[0] ? true : false;
              break
            }
          }

          if (this.isBackgroundSystemMaterialEnabled() && this.isCurrentPositionSelected) {
            this.getUIContext().animateTo({
              curve: curves.interpolatingSpring(0, 1, 195, 14),
            }, () => {
              this.selectedItemScale = { x: 1.01, y: 0.99 }
            })
          }
        })
        .onActionUpdate((event: GestureEvent) => {
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            // Non drag gesture in multi-select mode
            return
          }
          if (!this.isCurrentPositionSelected) {
            return
          }
          let fingerInfo = event.fingerList.find(Boolean)
          if (fingerInfo === void 0) {
            return
          }
          let selectedInfo = fingerInfo.localX
          if (!this.isPanGestureMoved && this.isMovedFromPanGestureStartPoint(fingerInfo.globalX,
            fingerInfo.globalY)) {
            this.isPanGestureMoved = true
          }

          if (this.isBackgroundSystemMaterialEnabled()) {
            const alg = this.layoutAlgorithm
            let buttonLength: number = Math.min(this.options.buttons.length, this.buttonItemsSize.length);
            const startX = Math.min(alg.getButtonX(0), alg.getButtonX(buttonLength - 1))
            const endX = Math.max(alg.getButtonX(0), alg.getButtonX(buttonLength - 1))

            const fingerOffset = this.getUIContext().vp2px(fingerInfo.globalX - this.panGestureStartPoint.x)
            const currentButtonX = alg.getButtonX(this.selectedIndexes[0])
            let nowX = fingerOffset + currentButtonX
            nowX = Math.max(startX, nowX)
            nowX = Math.min(endX, nowX)

            this.selectedItemOffsetX = this.getUIContext().px2vp(nowX - currentButtonX)
          } else {
            let buttonLength: number = Math.min(this.options.buttons.length, this.buttonItemsSize.length);
            for (let i = 0; i < buttonLength; i++) {
              selectedInfo = selectedInfo - (this.buttonItemsSize[i].width as number);
              if (selectedInfo < 0) {
                let realIndex = this.isShouldMirror() ? buttonLength - 1 - i : i;
                this.doSelectedChangeAnimate = true;
                this.selectedIndexes[0] = realIndex;
                this.doSelectedChangeAnimate = false;
                break;
              }
            }
            this.zoomScaleArray.forEach((_, index) => {
              if (index === this.selectedIndexes[0]) {
                animateTo({ curve: curves.interpolatingSpring(10, 1, 410, 38) }, () => {
                  this.zoomScaleArray[index] = 0.95
                })
              } else {
                animateTo({ curve: curves.interpolatingSpring(10, 1, 410, 38) }, () => {
                  this.zoomScaleArray[index] = 1
                })
              }
            })
          }
        })
        .onActionEnd((event: GestureEvent) => {
          this.isGestureInProgress = false;
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            // Non drag gesture in multi-select mode
            return
          }
          let fingerInfo = event.fingerList.find(Boolean)
          if (fingerInfo === void 0) {
            return
          }
          if (!this.isPanGestureMoved && this.isMovedFromPanGestureStartPoint(fingerInfo.globalX,
            fingerInfo.globalY)) {
            this.isPanGestureMoved = true
          }

          if (this.isBackgroundSystemMaterialEnabled()) {

            let selectedInfo = fingerInfo.localX
            let buttonLength: number = Math.min(this.options.buttons.length, this.buttonItemsSize.length);
            let realIndex: number = -1;
            for (let i = 0; i < buttonLength; i++) {
              selectedInfo = selectedInfo - (this.buttonItemsSize[i].width as number)
              if (selectedInfo < 0) {
                realIndex = this.isShouldMirror() ? buttonLength - 1 - i : i;
                break
              }
            }
            if (realIndex === -1) {
              realIndex = this.isShouldMirror() ? 0 : buttonLength - 1
            }
            this.getUIContext().animateTo({ curve: this.getSelectedChangeCurve() }, () => {
              this.selectedIndexes[0] = realIndex;
              this.selectedItemOffsetX = 0
            })
            this.finishSelectMaterialAnimation();

          } else {

            if (this.isMouseWheelScroll(event)) {
              let offset = event.offsetX !== 0 ? event.offsetX : event.offsetY
              this.doSelectedChangeAnimate = true

              // Reverse mouse wheel direction in mirrored layout
              let shouldMoveNext = this.isShouldMirror() ? offset > 0 : offset < 0;
              let shouldMovePrevious = this.isShouldMirror() ? offset < 0 : offset > 0;

              if (shouldMovePrevious && this.selectedIndexes[0] > 0) {
                this.selectedIndexes[0] -= 1;
              } else if (shouldMoveNext && this.selectedIndexes[0] < Math.min(this.options.buttons.length,
                this.buttonItemsSize.length) - 1) {
                this.selectedIndexes[0] += 1
              }
              this.doSelectedChangeAnimate = false
            }
            animateTo({ curve: curves.interpolatingSpring(10, 1, 410, 38) }, () => {
              this.zoomScaleArray[this.selectedIndexes[0]] = 1
            })
          }
          this.isCurrentPositionSelected = false
        })
        .onActionCancel(() => {
          this.isGestureInProgress = false;
          if (this.options === void 0 || this.options.buttons === void 0) {
            return
          }
          if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
            return
          }
          animateTo({ curve: curves.interpolatingSpring(10, 1, 410, 38) }, () => {
            this.zoomScaleArray[this.selectedIndexes[0]] = 1
          })
          this.isCurrentPositionSelected = false
          if (this.isBackgroundSystemMaterialEnabled()) {
            this.finishSelectMaterialAnimation();
          }
        })))
  }

  private isBackgroundSystemMaterialEnabled(): boolean {
    return this.options !== undefined &&
      this.options.backgroundSystemMaterial !== undefined;
  }

  startSelectMaterialAnimation() {
    if (!this.openSelectedItemSystemMaterial) {
      this.getUIContext().animateTo({
        curve: curves.interpolatingSpring(0, 1, 195, 14),
      }, () => {
        this.selectedItemScale = { x: 1.05, y: 1.18 }
        this.openSelectedItemSystemMaterial = true;
      })
    }
  }

  finishSelectMaterialAnimation() {
    if (this.openSelectedItemSystemMaterial) {
      this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 195, 14) }, () => {
        this.selectedItemScale = { x: 1.05, y: 1.18 }
      })
      this.getUIContext()
        .animateTo({
          curve: curves.interpolatingSpring(0, 1, 195, 14), delay: 300, onFinish: () => {
          }
        }, () => {
          this.openSelectedItemSystemMaterial = false
          this.selectedItemScale = undefined
        })
    }
  }

  getMaxFontSize(): number {
    if (typeof this.maxFontScale === void 0) {
      return DEFAULT_MAX_FONT_SCALE;
    }
    if (typeof this.maxFontScale === 'number') {
      return Math.max(Math.min(this.maxFontScale, MAX_MAX_FONT_SCALE), MIN_MAX_FONT_SCALE);
    }
    const resourceManager = this.getUIContext().getHostContext()?.resourceManager;
    if (!resourceManager) {
      return DEFAULT_MAX_FONT_SCALE;
    }
    try {
      return resourceManager.getNumber(this.maxFontScale.id);
    } catch (error) {
      console.error(`Ace SegmentButton getMaxFontSize, error: ${error.toString()}`);
      return DEFAULT_MAX_FONT_SCALE;
    }
  }

  getSelectedChangeCurve(): ICurve | null {
    if (this.options.type === 'capsule' && (this.options.multiply ?? false)) {
      return null
    }
    return curves.springMotion(0.347, 0.99)
  }

  updateAnimatedProperty(curve: ICurve | null) {
    let setAnimatedPropertyFunc = () => {
      this.selectedItemOffsetX = 0
      this.buttonItemsSelected.forEach((selected, index) => {
        this.buttonItemProperty[index].fontColor = selected ?
          this.options.selectedFontColor ?? (this.options.type === 'tab' ?
            segmentButtonTheme.TAB_SELECTED_FONT_COLOR : segmentButtonTheme.CAPSULE_SELECTED_FONT_COLOR) :
          this.options.fontColor ?? segmentButtonTheme.FONT_COLOR
      })
    }
    if (curve) {
      if (this.options.backgroundSystemMaterial) {
        this.getUIContext().animateTo({
          curve: curves.interpolatingSpring(0, 1, 195, 14),
        }, () => {
          this.selectedItemScale = { x: 1.01, y: 0.99 }
          this.openSelectedItemSystemMaterial = true;
        })
        this.getUIContext().animateTo({ curve: curve }, setAnimatedPropertyFunc)
        this.getUIContext().animateTo({
          curve: curves.interpolatingSpring(0, 1, 195, 14),
          delay: 200
        }, () => {
          this.openSelectedItemSystemMaterial = false;
        })
      } else {
        this.getUIContext().animateTo({ curve: curve }, setAnimatedPropertyFunc);
      }
    } else {
      setAnimatedPropertyFunc();
    }
    this.updateButtonFont();
  }

  updateButtonFont(): void {
    this.buttonItemsSelected.forEach((selected, index) => {
      const selectedFontSize = this.options.hasSelectedFontSize ? this.options.selectedFontSize: 
        (this.useAdaptiveLineHeight ? 
          segmentButtonTheme.ADAPTIVE_ITEM_FONT_SIZE : 
          segmentButtonTheme.SELECTED_FONT_SIZE);
      const normalFontSize = this.options.hasFontSize ? this.options.fontSize:  
        (this.useAdaptiveLineHeight ? segmentButtonTheme.ADAPTIVE_ITEM_FONT_SIZE : segmentButtonTheme.FONT_SIZE);
      this.buttonItemProperty[index].fontSize = selected ? selectedFontSize : normalFontSize;
      this.buttonItemProperty[index].fontWeight = selected ? this.options.selectedFontWeight ?? FontWeight.Medium :
        this.options.fontWeight ?? initFontWeight(FontWeight.Regular)
      this.buttonItemProperty[index].isSelected = selected
    })
  }
}

function resourceToNumber(context: Context | undefined, resource: Resource, defaultValue: number): number {
  if (!resource || !resource.type || !context) {
    console.error('[SegmentButton] failed: resource get fail.');
    return defaultValue;
  }
  let resourceManager = context?.resourceManager;
  if (!resourceManager) {
    console.error('[SegmentButton] failed to get resourceManager.');
    return defaultValue;
  }
  switch (resource.type) {
    case RESOURCE_TYPE_FLOAT:
    case RESOURCE_TYPE_INTEGER:
      try {
        if (resource.id !== -1) {
          return resourceManager.getNumber(resource);
        }
        return resourceManager.getNumberByName((resource.params as string[])[0].split('.')[2]);
      } catch (error) {
        console.error(`[SegmentButton] get resource error, return defaultValue`);
        return defaultValue;
      }
    default:
      return defaultValue;
  }
}

class LengthMetricsUtils {
  private static instance?: LengthMetricsUtils;

  private constructor() {
  }

  public static getInstance(): LengthMetricsUtils {
    if (!LengthMetricsUtils.instance) {
      LengthMetricsUtils.instance = new LengthMetricsUtils();
    }
    return LengthMetricsUtils.instance;
  }

  stringify(metrics: LengthMetrics): Dimension {
    switch (metrics.unit) {
      case LengthUnit.PX:
        return `${metrics.value}px`;
      case LengthUnit.VP:
        return `${metrics.value}vp`;
      case LengthUnit.FP:
        return `${metrics.value}fp`;
      case LengthUnit.PERCENT:
        return `${metrics.value}%`;
      case LengthUnit.LPX:
        return `${metrics.value}lpx`;
    }
  }

  isNaturalNumber(metrics: LengthMetrics): boolean {
    return metrics.value >= 0;
  }
}

function getBackgroundBorderRadius(options: SegmentButtonOptions, defaultRadius: number): Length {
  if (options.borderRadiusMode === BorderRadiusMode.CUSTOM) {
    // For capsule multi-select buttons, use itemBorderRadius
    if (options.type === 'capsule' && (options.multiply ?? false) && options.itemBorderRadius !== undefined) {
      return LengthMetricsUtils.getInstance().stringify(options.itemBorderRadius);
    } else if (options.backgroundBorderRadius !== undefined) {
      return LengthMetricsUtils.getInstance().stringify(options.backgroundBorderRadius);
    }
  }

  if (options.type === 'capsule' && (options.multiply ?? false)) {
    return options.iconTextRadius ?? options.iconTextBackgroundRadius ?? defaultRadius;
  }
  return options.iconTextBackgroundRadius ?? defaultRadius;
}

class SegmentButtonLayoutAlgorithm extends CustomLayoutAlgorithm {
  selectedIndex: number = -1
  componentPadding: number = 0
  multiply: boolean = false
  refHeight: number = 0
  selHeight: number = 0
  buttonWidth: number = 0
  rowSpace: number = 0
  shouldMirror: boolean = false
  buttonCount: number = 0

  getButtonX(index: number): number {
    const effectiveIndex = this.shouldMirror ? this.buttonCount - 1 - index : index
    return this.componentPadding + (this.buttonWidth + this.rowSpace) * effectiveIndex
  }

  onMeasure(self: FrameNode, constraint: LayoutConstraint): void {
    const childCount = self.getChildrenCount()
    if (childCount === 0) {
      self.setMeasuredSize({ width: 0, height: 0 })
      return
    }
    // Layer 2 (buttons Row) is the last child — measure it first to get reference size
    const buttonLayer = self.getChild(childCount - 1)
    if (buttonLayer) {
      buttonLayer.measure(constraint)
    }
    const refSize: Size = buttonLayer ? buttonLayer.getMeasuredSize() : { width: 0, height: 0 }

    // All buttons use layoutWeight(1) in Row({ space: 1 }) — calculate equal width
    let buttonWidth: number = 0
    if (buttonLayer) {
      this.buttonCount = buttonLayer.getChildrenCount()
      if (this.buttonCount > 0) {
        const contentWidth = refSize.width - 2 * this.componentPadding
        buttonWidth = (contentWidth - (this.buttonCount - 1) * this.rowSpace) / this.buttonCount
        if (buttonWidth < 0) {
          buttonWidth = 0
        }
      }
    }

    this.refHeight = refSize.height
    this.selHeight = Math.max(0, refSize.height - 2 * this.componentPadding)
    this.buttonWidth = buttonWidth

    const fullSizeConstraint: Size = { width: refSize.width, height: refSize.height }

    // Layer 0 (background): constrain to full reference size
    const bgChild = self.getChild(0)
    if (bgChild) {
      const bgConstraint: LayoutConstraint = {
        maxSize: fullSizeConstraint,
        minSize: fullSizeConstraint,
        percentReference: constraint.percentReference
      }
      bgChild.measure(bgConstraint)
    }

    // Layer 1 (selection indicator)
    if (childCount >= 2) {
      const selChild = self.getChild(1)
      if (selChild) {
        if (this.multiply) {
          // Multi-select: full size, inner Row uses layoutWeight + own padding
          const fullConstraint: LayoutConstraint = {
            maxSize: fullSizeConstraint,
            minSize: fullSizeConstraint,
            percentReference: constraint.percentReference
          }
          selChild.measure(fullConstraint)
        } else {
          // Single-select: constrain to single button size
          const selConstraint: LayoutConstraint = {
            maxSize: { width: this.buttonWidth, height: this.selHeight },
            minSize: { width: this.buttonWidth, height: this.selHeight },
            percentReference: constraint.percentReference
          }
          selChild.measure(selConstraint)
        }
      }
    }

    self.setMeasuredSize(refSize)
  }

  onLayout(self: FrameNode, position: Position): void {
    const childCount = self.getChildrenCount()

    // Layer 0 (background): full size at (0, 0)
    const bgChild = self.getChild(0)
    if (bgChild) {
      bgChild.layout({ x: 0, y: 0 })
    }

    // Layer 1 (selection indicator)
    if (childCount >= 2) {
      const selChild = self.getChild(1)
      if (selChild) {
        if (this.multiply) {
          selChild.layout({ x: 0, y: 0 })
        } else {
          selChild.layout({ x: this.getButtonX(Math.max(0, this.selectedIndex)), y: this.componentPadding })
        }
      }
    }

    // Layer 2 (buttons Row): full size at (0, 0)
    const btnLayer = self.getChild(childCount - 1)
    if (btnLayer) {
      btnLayer.layout({ x: 0, y: 0 })
    }

    self.setLayoutPosition({ x: position.x as number, y: position.y as number })
  }
}

class FocusStyleButtonModifier implements AttributeModifier<ButtonAttribute> {
  private stateStyleAction?: (isFocused: boolean) => void;

  constructor(stateStyleAction: (isFocused: boolean) => void) {
    this.stateStyleAction = stateStyleAction;
  }

  applyNormalAttribute(instance: ButtonAttribute): void {
    this.stateStyleAction && this.stateStyleAction(false);
  }

  applyFocusedAttribute(instance: ButtonAttribute): void {
    this.stateStyleAction && this.stateStyleAction(true);
  }
}