/*
 * Copyright (c) 2023-2025 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 { KeyCode } from '@ohos.multimodalInput.keyCode'
import MeasureText from '@ohos.measure'
import window from '@ohos.window'
import common from '@ohos.app.ability.common'
import { BusinessError } from '@kit.BasicServicesKit'
import { hilog } from '@kit.PerformanceAnalysisKit'
import { SymbolGlyphModifier, LengthMetrics } from '@kit.ArkUI'
import { i18n } from '@kit.LocalizationKit';

export interface TabTitleBarMenuItem {
  value: ResourceStr;
  symbolStyle?: SymbolGlyphModifier;
  isEnabled?: boolean;
  action?: () => void;
  label?: ResourceStr;
  accessibilityText?: ResourceStr;
  accessibilityLevel?: string;
  accessibilityDescription?: ResourceStr;
}

export interface TabTitleBarTabItem {
  title: ResourceStr;
  icon?: ResourceStr;
  symbolStyle?: SymbolGlyphModifier;
}

const PUBLIC_MORE = $r('sys.symbol.dot_grid_2x2')
const TEXT_EDITABLE_DIALOG = '18.3fp'
const IMAGE_SIZE = '64vp'
const MAX_DIALOG = '256vp'
const MIN_DIALOG = '216vp'
const RESOURCE_TYPE_SYMBOL: number = 40000;

class ButtonGestureModifier implements GestureModifier {
  public static readonly longPressTime: number = 500;
  public static readonly minFontSize: number = 1.75;
  public fontSize: number = 1;
  public controller: CustomDialogController | null = null;

  constructor(controller: CustomDialogController | null) {
    this.controller = controller;
  }

  applyGesture(event: UIGestureEvent): void {
    if (this.fontSize >= ButtonGestureModifier.minFontSize) {
      event.addGesture(
        new LongPressGestureHandler({ repeat: false, duration: ButtonGestureModifier.longPressTime })
          .onAction(() => {
            if (event) {
              this.controller?.open();
            }
          })
          .onActionEnd(() => {
            this.controller?.close();
          })
      )
    } else {
      event.clearGestures();
    }
  }
}

@Component
export struct TabTitleBar {
  tabItems: Array<TabTitleBarTabItem> = [];
  menuItems: Array<TabTitleBarMenuItem> = [];
  @BuilderParam swiperContent: () => void

  @State tabWidth: number = 0
  @State currentIndex: number = 0
  @State fontSize: number = 1

  static readonly totalHeight = 56
  static readonly correctionOffset = -40.0
  static readonly gradientMaskWidth = 24
  private static instanceCount = 0

  private menuSectionWidth = 0
  private tabOffsets: Array<number> = [];
  private imageWidths: Array<number> = [];

  private scroller: Scroller = new Scroller()
  private swiperController: SwiperController = new SwiperController()
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private leftContext2D: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private rightContext2D: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  @Builder
  GradientMaskArray(context2D: CanvasRenderingContext2D, position: Array<number>) {
    this.GradientMask(context2D, position[0], position[1], position[2], position[3]);
  }

  @Builder
  GradientMask(context2D: CanvasRenderingContext2D, x0: number, y0: number, x1: number, y1: number) {
    Column() {
      Canvas(context2D)
        .width(TabTitleBar.gradientMaskWidth)
        .height(TabTitleBar.totalHeight)
        .onReady(() => {
          let grad = context2D.createLinearGradient(x0, y0, x1, y1);
          grad.addColorStop(0.0, '#ffffffff')
          grad.addColorStop(1, '#00ffffff')
          context2D.fillStyle = grad
          context2D.fillRect(0, 0, TabTitleBar.gradientMaskWidth, TabTitleBar.totalHeight)
        })
    }
    .blendMode(BlendMode.DST_OUT)
    .width(TabTitleBar.gradientMaskWidth)
    .height(TabTitleBar.totalHeight)
  }

  @Builder
  emptyBuilder() {
  }

  aboutToAppear() {
    if (!this.swiperContent) {
      this.swiperContent = this.emptyBuilder;
    }
    this.tabItems.forEach((_elem) => {
      this.imageWidths.push(0)
    })
    this.loadOffsets()
  }

  loadOffsets() {
    this.tabOffsets.length = 0

    let tabOffset = 0
    this.tabOffsets.push(tabOffset)
    tabOffset += TabContentItem.marginFirst

    this.tabItems.forEach((tabItem, index) => {
      if (tabItem.icon !== undefined || tabItem.symbolStyle !== undefined) {
        if (Math.abs(this.imageWidths[index]) > TabContentItem.imageHotZoneWidth) {
          tabOffset += this.imageWidths[index]
        } else {
          tabOffset += TabContentItem.imageHotZoneWidth
        }
      } else {
        tabOffset += TabContentItem.paddingLeft
        tabOffset += px2vp(MeasureText.measureText({
          textContent: tabItem.title.toString(),
          fontSize: 18,
          fontWeight: FontWeight.Medium,
        }))
        tabOffset += TabContentItem.paddingRight
      }
      this.tabOffsets.push(tabOffset)
    })
  }

  private isRTL(): boolean {
    try {
      return i18n?.isRTL(i18n?.System?.getSystemLanguage()) ?? false;
    } catch (exception) {
      const code: number = (exception as BusinessError)?.code;
      const message: string = (exception as BusinessError)?.message;
      hilog.error(0x3900, 'AdvancedTabTitleBar', `Failed to check RTL status, code: ${code}, message: ${message}`);
      return false;
    }
  }

  build() {
    Column() {
      Flex({
        justifyContent: FlexAlign.SpaceBetween,
        alignItems: ItemAlign.Stretch
      }) {
        Stack({ alignContent: Alignment.End }) {
          Stack({ alignContent: Alignment.Start }) {
            Column() {
              List({ initialIndex: 0, scroller: this.scroller, space: 0 }) {
                ForEach(this.tabItems, (tabItem: TabTitleBarTabItem, index: number) => {
                  ListItem() {
                    TabContentItem({
                      item: tabItem,
                      index: index,
                      maxIndex: this.tabItems.length - 1,
                      currentIndex: this.currentIndex,
                      onCustomClick: (itemIndex) => this.currentIndex = itemIndex,
                      onImageComplete: (width) => {
                        this.imageWidths[index] = width
                        this.loadOffsets()
                      }
                    })
                  }
                })
              }
              .width('100%')
              .height(TabTitleBar.totalHeight)
              .constraintSize({ maxWidth: this.tabWidth })
              .edgeEffect(EdgeEffect.Spring)
              .listDirection(Axis.Horizontal)
              .scrollBar(BarState.Off)
            }
            this.GradientMaskArray(
              this.isRTL() ? this.rightContext2D : this.leftContext2D,
              this.isRTL() ?
                [TabTitleBar.gradientMaskWidth, TabTitleBar.totalHeight / 2, 0, TabTitleBar.totalHeight / 2] :
                [0, TabTitleBar.totalHeight / 2, TabTitleBar.gradientMaskWidth, TabTitleBar.totalHeight / 2]
            )
          }
          this.GradientMaskArray(
            this.isRTL() ? this.leftContext2D : this.rightContext2D,
            this.isRTL() ?
              [0, TabTitleBar.totalHeight / 2, TabTitleBar.gradientMaskWidth, TabTitleBar.totalHeight / 2] :
              [TabTitleBar.gradientMaskWidth, TabTitleBar.totalHeight / 2, 0, TabTitleBar.totalHeight / 2]
          )
        }
        .blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)

        if (this.menuItems !== undefined && this.menuItems.length > 0) {
          CollapsibleMenuSection({ menuItems: this.menuItems, index: 1 + TabTitleBar.instanceCount++ })
            .height(TabTitleBar.totalHeight)
            .onAreaChange((_oldValue, newValue) => {
              this.menuSectionWidth = Number(newValue.width)
            })
        }
      }
      .backgroundColor($r('sys.color.ohos_id_color_background'))
      .margin({ end: LengthMetrics.resource($r('sys.float.ohos_id_max_padding_end')) })
      .onAreaChange((_oldValue, newValue) => {
        this.tabWidth = Number(newValue.width) - this.menuSectionWidth
      })

      Column() {
        Swiper(this.swiperController) { this.swiperContent() }
        .index(this.currentIndex)
        .itemSpace(0)
        .indicator(false)
        .width('100%')
        .height('100%')
        .curve(Curve.Friction)
        .onChange((index) => {
          const offset = this.tabOffsets[index] + TabTitleBar.correctionOffset
          this.currentIndex = index
          this.scroller.scrollTo({
            xOffset: offset > 0 ? offset : 0,
            yOffset: 0,
            animation: {
              duration: 300,
              curve: Curve.EaseInOut,
            }
          })
        })
        .onAppear(() => {
          this.scroller.scrollToIndex(this.currentIndex)
          this.scroller.scrollBy(TabTitleBar.correctionOffset, 0)
        })
      }
    }
  }
}

@Component
struct CollapsibleMenuSection {
  menuItems: Array<TabTitleBarMenuItem> = [];
  index: number = 0;
  item: TabTitleBarMenuItem = {
    value: PUBLIC_MORE,
    symbolStyle: new SymbolGlyphModifier(PUBLIC_MORE),
    label: $r('sys.string.ohos_toolbar_more'),
  } as TabTitleBarMenuItem;
  minFontSize: number = 1.75;
  isFollowingSystemFontScale: boolean = false;
  maxFontScale: number = 1;
  systemFontScale?: number = 1;

  static readonly maxCountOfVisibleItems = 1
  private static readonly focusPadding = 4
  private static readonly marginsNum = 2
  private firstFocusableIndex = -1

  @State isPopupShown: boolean = false

  @State isMoreIconOnFocus: boolean = false
  @State isMoreIconOnHover: boolean = false
  @State isMoreIconOnClick: boolean = false
  @Prop @Watch('onFontSizeUpdated') fontSize: number = 1;

  dialogController: CustomDialogController | null = new CustomDialogController({
    builder: TabTitleBarDialog({
      cancel: () => {
      },
      confirm: () => {
      },
      tabTitleDialog: this.item,
      tabTitleBarDialog: this.item.label ? this.item.label : '',
      fontSize: this.fontSize,
    }),
    maskColor: Color.Transparent,
    isModal: true,
    customStyle: true,
  })

  @State buttonGestureModifier: ButtonGestureModifier = new ButtonGestureModifier(this.dialogController);

  getMoreIconFgColor() {
    return this.isMoreIconOnClick
      ? $r('sys.color.ohos_id_color_titlebar_icon_pressed')
      : $r('sys.color.ohos_id_color_titlebar_icon');
  }

  getMoreIconBgColor() {
    if (this.isMoreIconOnClick) {
      return $r('sys.color.ohos_id_color_click_effect');
    } else if (this.isMoreIconOnHover) {
      return $r('sys.color.ohos_id_color_hover');
    } else {
      return Color.Transparent;
    }
  }

  aboutToAppear() {
    try {
      let uiContent: UIContext = this.getUIContext();
      this.isFollowingSystemFontScale = uiContent.isFollowingSystemFontScale();
      this.maxFontScale = uiContent.getMaxFontScale();
    } catch (exception) {
      let code: number = (exception as BusinessError)?.code;
      let message: string = (exception as BusinessError)?.message;
      hilog.error(0x3900, 'AdvancedTabTitleBar', `Failed to decideFontScale,cause, code: ${code}, message: ${message}`);
    }
    this.menuItems.forEach((item, index) => {
      if (item.isEnabled && this.firstFocusableIndex === -1 &&
        index > CollapsibleMenuSection.maxCountOfVisibleItems - 2) {
        this.firstFocusableIndex = this.index * 1000 + index + 1
      }
    })
    this.fontSize = this.decideFontScale()
  }

  decideFontScale(): number {
    let uiContent: UIContext = this.getUIContext();
    this.systemFontScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1;
    if (!this.isFollowingSystemFontScale) {
      return 1;
    }
    return Math.min(this.systemFontScale, this.maxFontScale);
  }

  onFontSizeUpdated(): void {
    this.buttonGestureModifier.fontSize = this.fontSize;
  }

  build() {
    Column() {
      Row() {
        if (this.menuItems.length <= CollapsibleMenuSection.maxCountOfVisibleItems) {
          ForEach(this.menuItems, (item: TabTitleBarMenuItem, index: number) => {
            ImageMenuItem({ item: item, index: this.index * 1000 + index + 1 })
          })
        } else {
          ForEach(this.menuItems.slice(0, CollapsibleMenuSection.maxCountOfVisibleItems - 1),
            (item: TabTitleBarMenuItem, index: number) => {
              ImageMenuItem({ item: item, index: this.index * 1000 + index + 1 })
            })

          Button({ type: ButtonType.Normal, stateEffect: true }) {
            SymbolGlyph(PUBLIC_MORE)
              .fontSize(TabContentItem.symbolSize)
              .draggable(false)
              .fontColor([$r('sys.color.icon_primary')])
              .focusable(true)
          }
          .accessibilityText($r('sys.string.ohos_toolbar_more'))
          .width(ImageMenuItem.imageHotZoneWidth)
          .height(ImageMenuItem.imageHotZoneWidth)
          .borderRadius(ImageMenuItem.buttonBorderRadius)
          .foregroundColor(this.getMoreIconFgColor())
          .backgroundColor(this.getMoreIconBgColor())
          .stateStyles({
            focused: {
              .border({
                radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                width: ImageMenuItem.focusBorderWidth,
                color: $r('sys.color.ohos_id_color_focused_outline'),
                style: BorderStyle.Solid
              })
            },
            normal: {
              .border({
                radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                width: 0
              })
            }
          })
          .onFocus(() => this.isMoreIconOnFocus = true)
          .onBlur(() => this.isMoreIconOnFocus = false)
          .onHover((isOn) => this.isMoreIconOnHover = isOn)
          .onKeyEvent((event) => {
            if (event.keyCode !== KeyCode.KEYCODE_ENTER && event.keyCode !== KeyCode.KEYCODE_SPACE) {
              return
            }
            if (event.type === KeyType.Down) {
              this.isMoreIconOnClick = true
            }
            if (event.type === KeyType.Up) {
              this.isMoreIconOnClick = false
            }
          })
          .onTouch((event) => {
            if (event.type === TouchType.Down) {
              this.isMoreIconOnClick = true
            }
            if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
              this.isMoreIconOnClick = false
              if (this.fontSize >= this.minFontSize) {
                this.dialogController?.close()
              }
            }
          })
          .onClick(() => this.isPopupShown = true)
          .gestureModifier(this.buttonGestureModifier)
          .bindPopup(this.isPopupShown, {
            builder: this.popupBuilder,
            placement: Placement.Bottom,
            popupColor: Color.White,
            enableArrow: false,
            onStateChange: (e) => {
              this.isPopupShown = e.isVisible
              if (!e.isVisible) {
                this.isMoreIconOnClick = false
              }
            }
          })
        }
      }
    }
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Layoutable[], constraint: ConstraintSizeOptions): void {
    children.forEach((child) => {
      child.layout({ x: 0, y: 0 });
    })
    this.fontSize = this.decideFontScale();
  }

  @Builder
  popupBuilder() {
    Column() {
      ForEach(this.menuItems.slice(CollapsibleMenuSection.maxCountOfVisibleItems - 1, this.menuItems.length),
        (item: TabTitleBarMenuItem, index: number) => {
          ImageMenuItem({ item: item, index: this.index * 1000 +
          CollapsibleMenuSection.maxCountOfVisibleItems + index })
        })
    }
    .width(ImageMenuItem.imageHotZoneWidth + CollapsibleMenuSection.focusPadding * CollapsibleMenuSection.marginsNum)
    .margin({ top: CollapsibleMenuSection.focusPadding, bottom: CollapsibleMenuSection.focusPadding })
    .onAppear(() => {
      focusControl.requestFocus(ImageMenuItem.focusablePrefix + this.firstFocusableIndex);
    })
  }
}

@Component
struct TabContentItem {
  item: TabTitleBarTabItem = { title: '' };
  index: number = 0;
  maxIndex: number = 0;
  onCustomClick?: (index: number) => void;
  onImageComplete?: (width: number) => void;

  @Prop currentIndex: number;

  @State isOnFocus: boolean = false;
  @State isOnHover: boolean = false;
  @State isOnClick: boolean = false;
  @State tabWidth: number = 0;

  @State imageWidth: number = 24;
  @State imageHeight: number = 24;

  static readonly imageSize = 24;
  static readonly symbolSize = '24vp';
  static readonly imageHotZoneWidth = 48;
  static readonly imageMagnificationFactor = 1.4;
  static readonly buttonBorderRadius = 8;
  static readonly focusBorderWidth = 2;
  static readonly paddingLeft = 8;
  static readonly paddingRight = 8;
  static readonly marginFirst = 16;

  getBgColor() {
    if (this.isOnClick) {
      return $r('sys.color.ohos_id_color_click_effect');
    } else if (this.isOnHover) {
      return $r('sys.color.ohos_id_color_hover');
    } else {
      return Color.Transparent;
    }
  }

  getBorderAttr(): BorderOptions {
    if (this.isOnFocus) {
      return {
        radius: $r('sys.float.ohos_id_corner_radius_clicked'),
        width: TabContentItem.focusBorderWidth,
        color: $r('sys.color.ohos_id_color_focused_outline'),
        style: BorderStyle.Solid,
      }
    }
    return { width: 0 }
  }

  getImageScaleFactor(): number {
    return this.index === this.currentIndex ? TabContentItem.imageMagnificationFactor : 1;
  }

  getImageLayoutWidth(): number {
    return TabContentItem.imageSize / Math.max(this.imageHeight, 1.0) * this.imageWidth;
  }

  private toStringFormat(resource: ResourceStr | undefined): string | undefined {
    if (typeof resource === 'string') {
      return resource;
    } else if (typeof resource === 'undefined') {
      return '';
    } else {
      let resourceString: string = '';
      try {
        resourceString = getContext()?.resourceManager?.getStringSync(resource);
      } catch (err) {
        let code: number = (err as BusinessError)?.code;
        let message: string = (err as BusinessError)?.message;
        hilog.error(0x3900, 'AdvancedTabTitleBar', `Failed to TabTitleBar toStringFormat,code: ${code},message:${message}`);
      }
      return resourceString;
    }
  }

  build() {
    Stack() {
      Row() {
        Column() {
          if (this.item.icon === undefined && this.item.symbolStyle === undefined) {
            Text(this.item.title)
              .fontSize(this.index === this.currentIndex
                ? $r('sys.float.ohos_id_text_size_headline7')
                : $r('sys.float.ohos_id_text_size_headline9'))
              .fontColor(this.index === this.currentIndex
                ? $r('sys.color.ohos_id_color_titlebar_text')
                : $r('sys.color.ohos_id_color_titlebar_text_off'))
              .fontWeight(FontWeight.Medium)
              .focusable(true)
              .animation({ duration: 300 })
              .padding({
                top: this.index === this.currentIndex ? 6 : 10,
                left: TabContentItem.paddingLeft,
                bottom: 2,
                right: TabContentItem.paddingRight
              })
              .onFocus(() => this.isOnFocus = true)
              .onBlur(() => this.isOnFocus = false)
              .onHover((isOn) => this.isOnHover = isOn)
              .onKeyEvent((event) => {
                if (event.keyCode !== KeyCode.KEYCODE_ENTER && event.keyCode !== KeyCode.KEYCODE_SPACE) {
                  return
                }
                if (event.type === KeyType.Down) {
                  this.isOnClick = true
                }
                if (event.type === KeyType.Up) {
                  this.isOnClick = false
                }
              })
              .onTouch((event) => {
                if (event.type === TouchType.Down) {
                  this.isOnClick = true
                }
                if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
                  this.isOnClick = false
                }
              })
              .onClick(() => this.onCustomClick && this.onCustomClick(this.index))
              .accessibilitySelected(this.index === this.currentIndex)
          } else {
            Row() {
              if (this.item.symbolStyle) {
                SymbolGlyph()
                  .fontColor([$r('sys.color.icon_primary')])
                  .attributeModifier(this.item.symbolStyle)
                  .fontSize(TabContentItem.symbolSize)
                  .width(this.getImageLayoutWidth())
                  .height(TabContentItem.imageSize)
                  .accessibilityText(this.item.title as string)
                  .scale({
                    x: this.getImageScaleFactor(),
                    y: this.getImageScaleFactor()
                  })
                  .animation({ duration: 300 })
                  .hitTestBehavior(HitTestMode.None)
                  .focusable(true)
                  .symbolEffect(new SymbolEffect(), false)
              } else {
                if (Util.isSymbolResource(this.item.icon)) {
                  SymbolGlyph(this.item.icon as Resource)
                    .fontColor([$r('sys.color.icon_primary')])
                    .fontSize(TabContentItem.symbolSize)
                    .width(this.getImageLayoutWidth())
                    .height(TabContentItem.imageSize)
                    .accessibilityText(this.item.title as string)
                    .scale({
                      x: this.getImageScaleFactor(),
                      y: this.getImageScaleFactor()
                    })
                    .animation({ duration: 300 })
                    .hitTestBehavior(HitTestMode.None)
                    .focusable(true)
                } else {
                  Image(this.item.icon)
                    .alt(this.item.title)
                    .width(this.getImageLayoutWidth())
                    .height(TabContentItem.imageSize)
                    .objectFit(ImageFit.Fill)
                    .accessibilityText(this.item.title as string)
                    .scale({
                      x: this.getImageScaleFactor(),
                      y: this.getImageScaleFactor()
                    })
                    .animation({ duration: 300 })
                    .hitTestBehavior(HitTestMode.None)
                    .focusable(true)
                    .onComplete((event) => {
                      if (!this.onImageComplete) {
                        return
                      }
                      this.imageWidth = px2vp(event?.width);
                      this.imageHeight = px2vp(event?.height);
                      this.onImageComplete(px2vp(event?.componentWidth) +
                      TabContentItem.paddingLeft + TabContentItem.paddingRight);
                    })
                    .onError((event) => {
                      if (!this.onImageComplete) {
                        return
                      }
                      this.onImageComplete(px2vp(event.componentWidth) +
                      TabContentItem.paddingLeft + TabContentItem.paddingRight)
                    })
                }
              }
            }
            .width(this.getImageLayoutWidth() * this.getImageScaleFactor() +
            TabContentItem.paddingLeft + TabContentItem.paddingRight)
            .constraintSize({
              minWidth: TabContentItem.imageHotZoneWidth,
              minHeight: TabContentItem.imageHotZoneWidth
            })
            .animation({ duration: 300 })
            .justifyContent(FlexAlign.Center)
            .onFocus(() => this.isOnFocus = true)
            .onBlur(() => this.isOnFocus = false)
            .onHover((isOn) => this.isOnHover = isOn)
            .onKeyEvent((event) => {
              if (event.keyCode !== KeyCode.KEYCODE_ENTER && event.keyCode !== KeyCode.KEYCODE_SPACE) {
                return;
              }
              if (event.type === KeyType.Down) {
                this.isOnClick = true;
              }
              if (event.type === KeyType.Up) {
                this.isOnClick = false;
              }
            })
            .onTouch((event) => {
              if (event.type === TouchType.Down) {
                this.isOnClick = true;
              }
              if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
                this.isOnClick = false;
              }
            })
            .onClick(() => this.onCustomClick && this.onCustomClick(this.index))
            .accessibilitySelected(this.index === this.currentIndex)
          }
        }
        .justifyContent(FlexAlign.Center)
      }
      .height(TabTitleBar.totalHeight)
      .alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.Center)
      .borderRadius(TabContentItem.buttonBorderRadius)
      .backgroundColor(this.getBgColor())
      .onAreaChange((_oldValue, newValue) => {
        this.tabWidth = Number(newValue.width)
      })

      if (this.isOnFocus && this.tabWidth > 0) {
        Row()
          .width(this.tabWidth)
          .height(TabTitleBar.totalHeight)
          .hitTestBehavior(HitTestMode.None)
          .borderRadius(TabContentItem.buttonBorderRadius)
          .stateStyles({
            focused: {
              .border(this.getBorderAttr())
            },
            normal: {
              .border({
                radius: $r('sys.float.ohos_id_corner_radius_clicked'),
                width: 0,
              })
            }
          })
      }
    }
    .margin({
      left: this.index === 0 ? TabContentItem.marginFirst : 0,
      right: this.index === this.maxIndex ? 12 : 0,
    })
  }
}

@Component
struct ImageMenuItem {
  item: TabTitleBarMenuItem = { value: '' };
  index: number = 0;

  static readonly imageSize = 24;
  static readonly imageHotZoneWidth = 48;
  static readonly buttonBorderRadius = 8;
  static readonly focusBorderWidth = 2;
  static readonly disabledImageOpacity = 0.4;
  static readonly focusablePrefix = 'Id-TabTitleBar-ImageMenuItem-';

  @State isOnFocus: boolean = false;
  @State isOnHover: boolean = false;
  @State isOnClick: boolean = false;

  getFgColor() {
    return this.isOnClick
      ? $r('sys.color.ohos_id_color_titlebar_icon_pressed')
      : $r('sys.color.ohos_id_color_titlebar_icon');
  }

  getBgColor() {
    if (this.isOnClick) {
      return $r('sys.color.ohos_id_color_click_effect');
    } else if (this.isOnHover) {
      return $r('sys.color.ohos_id_color_hover');
    } else {
      return Color.Transparent;
    }
  }

  private toStringFormat(resource: ResourceStr | undefined): string | undefined {
    if (typeof resource === 'string') {
      return resource;
    } else if (typeof resource === 'undefined') {
      return '';
    } else {
      let resourceString: string = '';
      try {
        resourceString = getContext()?.resourceManager?.getStringSync(resource);
      } catch (err) {
        let code: number = (err as BusinessError)?.code;
        let message: string = (err as BusinessError)?.message;
        hilog.error(0x3900, 'AdvancedTabTitleBar', `Failed to TabTitleBar toStringFormat,code: ${code},message:${message}`);
      }
      return resourceString;
    }
  }

  private getAccessibilityReadText(): string | undefined {
    if (this.item.value === PUBLIC_MORE) {
      try {
        return getContext()?.resourceManager?.getStringByNameSync('ohos_toolbar_more');
      } catch (err) {
        let code: number = (err as BusinessError)?.code;
        let message: string = (err as BusinessError)?.message;
        hilog.error(0x3900, 'AdvancedTabTitleBar', `Failed to TabTitleBar toStringFormat,code: ${code},message:${message}`);
      }
    } else if (this.item.accessibilityText) {
      return this.item.accessibilityText as string;
    } else if (this.item.label) {
      return this.item.label as string;
    }
    return ' ';
  }

  build() {
    Button({ type: ButtonType.Normal, stateEffect: this.item.isEnabled }) {
      if (this.item.symbolStyle) {
        SymbolGlyph()
          .fontColor([$r('sys.color.font_primary')])
          .attributeModifier(this.item.symbolStyle)
          .fontSize(TabContentItem.symbolSize)
          .draggable(false)
          .focusable(this.item?.isEnabled)
          .key(ImageMenuItem.focusablePrefix + this.index)
          .symbolEffect(new SymbolEffect(), false)
      } else {
        if (Util.isSymbolResource(this.item.value)) {
          SymbolGlyph(this.item.value as Resource)
            .fontColor([$r('sys.color.font_primary')])
            .fontSize(TabContentItem.symbolSize)
            .draggable(false)
            .focusable(this.item?.isEnabled)
            .key(ImageMenuItem.focusablePrefix + this.index)
        } else {
          Image(this.item.value)
            .width(ImageMenuItem.imageSize)
            .height(ImageMenuItem.imageSize)
            .focusable(this.item.isEnabled)
            .key(ImageMenuItem.focusablePrefix + this.index)
            .draggable(false)
        }
      }
    }
    .accessibilityText(this.getAccessibilityReadText())
    .accessibilityLevel(this.item?.accessibilityLevel ?? 'auto')
    .accessibilityDescription(this.item?.accessibilityDescription as string)
    .width(ImageMenuItem.imageHotZoneWidth)
    .height(ImageMenuItem.imageHotZoneWidth)
    .borderRadius(ImageMenuItem.buttonBorderRadius)
    .foregroundColor(this.getFgColor())
    .backgroundColor(this.getBgColor())
    .enabled(this.item.isEnabled ? this.item.isEnabled : false)
    .stateStyles({
      focused: {
        .border({
          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
          width: ImageMenuItem.focusBorderWidth,
          color: $r('sys.color.ohos_id_color_focused_outline'),
          style: BorderStyle.Solid,
        })
      },
      normal: {
        .border({
          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
          width: 0,
        })
      }
    })
    .onFocus(() => {
      if (!this.item.isEnabled) {
        return;
      }
      this.isOnFocus = true;
    })
    .onBlur(() => this.isOnFocus = false)
    .onHover((isOn) => {
      if (!this.item.isEnabled) {
        return;
      }
      this.isOnHover = isOn;
    })
    .onKeyEvent((event) => {
      if (!this.item.isEnabled) {
        return;
      }
      if (event.keyCode !== KeyCode.KEYCODE_ENTER && event.keyCode !== KeyCode.KEYCODE_SPACE) {
        return;
      }
      if (event.type === KeyType.Down) {
        this.isOnClick = true;
      }
      if (event.type === KeyType.Up) {
        this.isOnClick = false;
      }
    })
    .onTouch((event) => {
      if (!this.item.isEnabled) {
        return;
      }
      if (event.type === TouchType.Down) {
        this.isOnClick = true;
      }
      if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
        this.isOnClick = false;
      }
    })
    .onClick(() => this.item.isEnabled && this.item.action && this.item.action())
  }
}

/**
 *  TabTitleBarDialog
 */
@CustomDialog
struct TabTitleBarDialog {
  tabTitleDialog: TabTitleBarMenuItem = { value: '' };
  callbackId: number | undefined = undefined;
  tabTitleBarDialog?: ResourceStr = '';
  mainWindowStage: window.Window | undefined = undefined;
  controller?: CustomDialogController
  minFontSize: number = 1.75;
  maxFontSize: number = 3.2;
  screenWidth: number = 640;
  verticalScreenLines: number = 6;
  horizontalsScreenLines: number = 1;
  @StorageLink('mainWindow') mainWindow: Promise<window.Window> | undefined = undefined;
  @State fontSize: number = 1;
  @State maxLines: number = 1;
  @StorageProp('windowStandardHeight') windowStandardHeight: number = 0;
  cancel: () => void = () => {
  }
  confirm: () => void = () => {
  }

  build() {
    if (this.tabTitleBarDialog) {
      Column() {
        if (this.tabTitleDialog.symbolStyle) {
          SymbolGlyph()
            .fontColor([$r('sys.color.font_primary')])
            .attributeModifier(this.tabTitleDialog.symbolStyle)
            .fontSize(IMAGE_SIZE)
            .draggable(false)
            .focusable(this.tabTitleDialog?.isEnabled)
            .margin({
              top: $r('sys.float.padding_level24'),
              bottom: $r('sys.float.padding_level8'),
            })
            .symbolEffect(new SymbolEffect(), false)
        } else if (this.tabTitleDialog.value) {
          if (Util.isSymbolResource(this.tabTitleDialog.value)) {
            SymbolGlyph(this.tabTitleDialog.value as Resource)
              .fontColor([$r('sys.color.font_primary')])
              .fontSize(IMAGE_SIZE)
              .draggable(false)
              .focusable(this.tabTitleDialog?.isEnabled)
              .margin({
                top: $r('sys.float.padding_level24'),
                bottom: $r('sys.float.padding_level8'),
              })
          } else {
            Image(this.tabTitleDialog.value)
              .width(IMAGE_SIZE)
              .height(IMAGE_SIZE)
              .margin({
                top: $r('sys.float.padding_level24'),
                bottom: $r('sys.float.padding_level8'),
              })
              .fillColor($r('sys.color.icon_primary'))
          }
        }
        Column() {
          Text(this.tabTitleBarDialog)
            .fontSize(TEXT_EDITABLE_DIALOG)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .maxLines(this.maxLines)
            .width('100%')
            .textAlign(TextAlign.Center)
            .fontColor($r('sys.color.font_primary'))
        }
        .width('100%')
        .padding({
          left: $r('sys.float.padding_level4'),
          right: $r('sys.float.padding_level4'),
          bottom: $r('sys.float.padding_level12'),
        })
      }
      .width(this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG)
      .constraintSize({ minHeight: this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG })
      .backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK, undefined, { disableSystemAdaptation: true })
      .shadow(ShadowStyle.OUTER_DEFAULT_LG)
      .borderRadius($r('sys.float.corner_radius_level10'))
    } else {
      Column() {
        if (this.tabTitleDialog.symbolStyle) {
          SymbolGlyph()
            .fontColor([$r('sys.color.font_primary')])
            .attributeModifier(this.tabTitleDialog.symbolStyle)
            .fontSize(IMAGE_SIZE)
            .draggable(false)
            .focusable(this.tabTitleDialog?.isEnabled)
            .symbolEffect(new SymbolEffect(), false)
        } else if (this.tabTitleDialog.value){
          if (Util.isSymbolResource(this.tabTitleDialog.value)) {
            SymbolGlyph(this.tabTitleDialog.value as Resource)
              .fontColor([$r('sys.color.font_primary')])
              .fontSize(IMAGE_SIZE)
              .draggable(false)
              .focusable(this.tabTitleDialog?.isEnabled)
              .margin({
                top: $r('sys.float.padding_level24'),
                bottom: $r('sys.float.padding_level8'),
              })
          } else {
            Image(this.tabTitleDialog.value)
              .width(IMAGE_SIZE)
              .height(IMAGE_SIZE)
              .fillColor($r('sys.color.icon_primary'))
          }
        }
      }
      .width(this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG)
      .constraintSize({ minHeight: this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG })
      .backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK, undefined, { disableSystemAdaptation: true })
      .shadow(ShadowStyle.OUTER_DEFAULT_LG)
      .borderRadius($r('sys.float.corner_radius_level10'))
      .justifyContent(FlexAlign.Center)
    }
  }

  async aboutToAppear(): Promise<void> {
    try {
      let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
      this.mainWindowStage = context.windowStage.getMainWindowSync();
      let properties: window.WindowProperties = this.mainWindowStage.getWindowProperties();
      let rect = properties.windowRect;
      if (px2vp(rect.height) > this.screenWidth) {
        this.maxLines = this.verticalScreenLines;
      } else {
        this.maxLines = this.horizontalsScreenLines;
      }

    } catch (exception) {
      let code: number = (exception as BusinessError)?.code;
      let message: string = (exception as BusinessError)?.message;
      hilog.error(0x3900, 'AdvancedTabTitleBar', `Failed to getMainWindowSync,cause, code: ${code}, message: ${message}`);
    }
  }
}

class Util {
  public static isSymbolResource(resourceStr: ResourceStr | undefined): boolean {
    if (!Util.isResourceType(resourceStr)) {
      return false;
    }
    let resource = resourceStr as Resource;
    return resource.type === RESOURCE_TYPE_SYMBOL;
  }

  public static isResourceType(resource: ResourceStr | Resource | undefined): boolean {
    if (!resource) {
      return false;
    }
    if (typeof resource === 'string' || typeof resource === 'undefined') {
      return false;
    }
    return true;
  }
}