/*
 * Copyright (c) 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 { LeftListItem } from './LeftListItem';
import { DEFAULT_TOP_LIST_ITEM_FONT_COLOR, TopListItem } from './TopListItem';
import { RightSubList } from './RightSubList';
import { scheduleRowPrebuild } from '../common/RowPrebuildCallback';
import { BaseTableViewModel } from '../viewmodel/BaseTableViewModel';
import { CommonConstants } from '../constant/CommonConstants';
import { TableGroup, TableRow } from '../model/TableDataModel';

/**
 * Default top list header font color
 * Used to set font_primary color
 */
export const DEFAULT_TOP_LIST_HEADER_FONT_COLOR: ResourceColor = $r('sys.color.font_primary');

const RIGHT_TABLE_ROW_REUSE_ID: string = 'right_table_row';

// [Start TableSceneConfig]
/**
 * Table scene configuration interface
 * Used to customize display differences for different scenarios
 */
export interface TableSceneConfig {
  /**
   * Whether to use grouped list (ListItemGroup + sticky headers).
   * true: grouped list for multi-section tables (e.g. car spec).
   * false: flat list without ListItemGroup (e.g. stock table).
   */
  showGroupHeader: boolean;

  /**
   * Whether to show top list top border
   */
  showTopListTopBorder: boolean;

  /**
   * Whether to show top list bottom border
   */
  showTopListBottomBorder: boolean;

  /**
   * Whether to show vertical divider lines (column dividers)
   */
  showVerticalLine?: boolean;

  /**
   * Text style configuration
   */
  textStyleConfig?: TextStyleConfig;

  /**
   * Layout dimension configuration
   */
  layoutConfig: TableLayoutConfig;
}

// [End TableSceneConfig]
// [Start TableLayoutConfig]
/**
 * Table layout configuration interface
 * Defines the dimensions of each table area to ensure row and column alignment
 */
export interface TableLayoutConfig {
  /**
   * Top horizontal list height (vp), also controls left title area height
   */
  topListHeight: number;

  /**
   * Left vertical list width (vp), also controls top title area width
   */
  leftListWidth: number;

  /**
   * Sub-component width (vp), shared by top list items and bottom sub-list items to ensure column alignment
   */
  listItemWidth: number;

  /**
   * Sub-list row height (vp), shared by left list rows and bottom sub-list rows to ensure row alignment
   */
  subListHeight: number;

  /**
   * Group header height (vp)
   */
  groupHeaderHeight?: number;
}

// [End TableLayoutConfig]

/**
 * Text style configuration interface
 * Used to customize text styles for each area
 */
export interface TextStyleConfig {
  /**
   * Top list header text color
   * When not set, uses default color: font_primary
   */
  topListHeaderFontColor?: ResourceColor;

  /**
   * Top list header font size
   */
  topListHeaderFontSize?: ResourceStr | number;

  /**
   * Top list header font weight
   */
  topListHeaderFontWeight?: FontWeight;

  /**
   * Top list item text color
   * When not set, uses default color: font_primary
   */
  topListItemFontColor?: ResourceColor;

  /**
   * Top list item font size
   */
  topListItemFontSize?: ResourceStr | number;

  /**
   * Top list item font weight
   */
  topListItemFontWeight?: FontWeight;

  /**
   * Cell text color
   * When not set, uses default color: font_secondary
   * When data has dynamic colors (e.g., stock rise/fall), dynamic colors take priority
   */
  cellItemFontColor?: ResourceColor;

  /**
   * Cell font size
   */
  cellItemFontSize?: ResourceStr | number;
}

// [End TableConfig]
/**
 * Dual scroll table universal component
 * Provides top horizontal list + bottom left vertical list + bottom right dual scroll list layout
 * Supports configuration of group headers, borders, and other display differences
 */
@ComponentV2
  // [Start DualScrollTable]
export struct DualScrollTable {
  /**
   * ViewModel instance, provides data and scroll synchronization logic,
   * must be provided externally with concrete implementation
   */
  @Param @Require viewModel: BaseTableViewModel;
  /**
   * Scene configuration
   */
  @Param config: TableSceneConfig = {
    // [StartExclude DualScrollTable]
    showGroupHeader: false,
    showTopListTopBorder: true,
    showTopListBottomBorder: false,
    showVerticalLine: true,
    layoutConfig: {
      topListHeight: 80,
      leftListWidth: 100,
      listItemWidth: 155,
      subListHeight: 80,
      groupHeaderHeight: 44
    }
    // [EndExclude DualScrollTable]
  };

  // [StartExclude DualScrollTable]

  /**
   * Get whether to show vertical divider line
   */
  private getShowVerticalLine(): boolean {
    return this.config.showVerticalLine ?? true;
  }

  private getDefaultCellFontColor(): ResourceColor {
    return this.config.textStyleConfig?.cellItemFontColor ?? $r('sys.color.font_secondary');
  }

  private refreshTableLayout(): void {
    this.viewModel.refreshHorizontalContentWidth(this.config.layoutConfig.listItemWidth);
  }

  aboutToAppear(): void {
    this.refreshTableLayout();
    // Register idle prebuild after page show to warm the pool with full-row BuilderNodes
    scheduleRowPrebuild(
      this.getUIContext(),
      this.viewModel.flatRowDataArray,
      this.config.layoutConfig.subListHeight,
      this.config.layoutConfig.listItemWidth,
      this.getShowVerticalLine(),
      this.getDefaultCellFontColor()
    );
  }

  // [EndExclude DualScrollTable]
  build() {
    Column() {
      this.TopList();
      Row() {
        this.LeftList();
        this.RightList();
      }
      .layoutWeight(1)
    }
  }

  // [StartExclude DualScrollTable]
  /**
   * Top horizontal scroll list
   */
  // [Start TopListTag]
  // [Start TopListDesc]
  @Builder
  TopList() {
    Row() {
      this.TopListHeader(this.viewModel.leftTitle);
      List({ scroller: this.viewModel.topListScroller }) {
        // [StartExclude TopListTag]
        Repeat(this.viewModel.topListData)
          .each((item: RepeatItem<ResourceStr>) => {
            ListItem() {
              TopListItem({
                info: item.item,
                itemWidth: this.config.layoutConfig.listItemWidth,
                fontColor: this.config.textStyleConfig?.topListItemFontColor ?? DEFAULT_TOP_LIST_ITEM_FONT_COLOR,
                fontSize: this.config.textStyleConfig?.topListItemFontSize ?? $r('sys.float.Body_L'),
                fontWeight: this.config.textStyleConfig?.topListItemFontWeight ?? FontWeight.Medium
              })
            }
          })
          .key((_item: ResourceStr, index: number) => `top_${index}`)
          .virtualScroll()
        // [EndExclude TopListTag]
      }
      // [StartExclude TopListTag]
      .cachedCount(CommonConstants.LIST_HORIZONTAL_CACHED_COUNT)
      .listDirection(Axis.Horizontal)
      .width(`calc(100% - ${this.config.layoutConfig.leftListWidth}vp)`)
      .height('100%')
      // [StartExclude TopListDesc]
      .edgeEffect(EdgeEffect.None)
      .scrollBar(BarState.Off)
      .divider({
        strokeWidth: this.getShowVerticalLine() ? CommonConstants.LINE_STROKE_WIDTH : 0,
        color: $r('sys.color.comp_divider')
      })
      // [EndExclude TopListTag]
      // Triggered before list scrolls, the list will scroll according to the actual scroll amount returned
      .onScrollFrameBegin((offset: number, _state: ScrollState) => {
        this.viewModel.syncTopListScrollToSubList(offset);
        return { offsetRemain: offset };
      })
    }
    // [StartExclude TopListTag]
    .height(this.config.layoutConfig.topListHeight)
    .borderWidth({
      top: this.config.showTopListTopBorder ? CommonConstants.LINE_STROKE_WIDTH : 0,
      bottom: this.config.showTopListBottomBorder ? CommonConstants.LINE_STROKE_WIDTH : 0
    })
    .borderColor($r('sys.color.comp_divider'))

    // [EndExclude TopListTag]
    // [EndExclude TopListDesc]
  }

  // [End TopListTag]
  // [End TopListDesc]

  /**
   * Bottom left vertical scroll list (parameter name column)
   */
  @Builder
  LeftList() {
    if (this.config.showGroupHeader) {
      this.LeftGroupList();
    } else {
      this.LeftFlatList();
    }
  }

  // [Start LeftListTag]
  @Builder
  LeftGroupList() {
    List({ scroller: this.viewModel.leftListScroller }) {
      // [StartExclude LeftListTag]
      Repeat(this.viewModel.groupDataArray)
        .each((group: RepeatItem<TableGroup>) => {
          ListItemGroup({ header: this.LeftGroupHeader(group.item.sticky) }) {
            Repeat(group.item.sub)
              .each((subItem: RepeatItem<TableRow>) => {
                ListItem() {
                  this.LeftListItemContent(subItem.item);
                }
              })
              .key((item: TableRow) => item.id)
              .virtualScroll()
          }
        })
        .key((item: TableGroup) => item.id)
        .virtualScroll()
      // [EndExclude LeftListTag]
    }
    .onScrollFrameBegin((offset: number, _state: ScrollState) => {
      this.viewModel.syncLeftListScrollToRightList(offset);
      return { offsetRemain: offset };
    })
    // [StartExclude LeftListTag]
    .cachedCount(CommonConstants.LIST_VERTICAL_CACHED_COUNT)
    .scrollBar(BarState.Off)
    .edgeEffect(EdgeEffect.None)
    .listDirection(Axis.Vertical)
    .sticky(StickyStyle.Header)
    .width(`${this.config.layoutConfig.leftListWidth}vp`)
    .height('100%')
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])

    // [EndExclude LeftListTag]
  }

  // [End LeftListTag]

  @Builder
  LeftFlatList() {
    List({ scroller: this.viewModel.leftListScroller }) {
      Repeat(this.viewModel.flatRowDataArray)
        .each((subItem: RepeatItem<TableRow>) => {
          ListItem() {
            this.LeftListItemContent(subItem.item);
          }
        })
        .key((item: TableRow) => item.id)
        .virtualScroll()
    }
    .onScrollFrameBegin((offset: number, _state: ScrollState) => {
      this.viewModel.syncLeftListScrollToRightList(offset);
      return { offsetRemain: offset };
    })
    .cachedCount(CommonConstants.LIST_VERTICAL_CACHED_COUNT)
    .scrollBar(BarState.Off)
    .edgeEffect(EdgeEffect.None)
    .listDirection(Axis.Vertical)
    .width(`${this.config.layoutConfig.leftListWidth}vp`)
    .height('100%')
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
  }

  @Builder
  LeftListItemContent(subItem: TableRow) {
    LeftListItem({
      name: subItem.part,
      itemWidth: this.config.layoutConfig.leftListWidth,
      itemHeight: this.config.layoutConfig.subListHeight,
      showVerticalLine: this.getShowVerticalLine()
    })
  }

  /**
   * Bottom right vertical scroll list (parameter value column)
   */
  @Builder
  RightList() {
    if (this.config.showGroupHeader) {
      this.RightGroupList();
    } else {
      this.RightFlatList();
    }
  }

  // [Start RightListTag]
  // [Start RightScrollTag]
  @Builder
  RightGroupList() {
    Scroll(this.viewModel.rightAreaScroller) {
      // [StartExclude RightScrollTag]
      List({ scroller: this.viewModel.rightListScroller }) {
        // [StartExclude RightListTag]
        Repeat(this.viewModel.groupDataArray)
          .each((group: RepeatItem<TableGroup>) => {
            ListItemGroup({ header: this.RightGroupHeader() }) {
              Repeat(group.item.sub)
                .each((subItem: RepeatItem<TableRow>) => {
                  ListItem() {
                    this.RightListItemContent(subItem.item);
                  }
                })
                .key((item: TableRow) => item.id)
                .virtualScroll({ reusable: false })
            }
          })
          .key((item: TableGroup) => item.id)
          .virtualScroll({ reusable: false })
        // [EndExclude RightListTag]
      }
      .onScrollFrameBegin((offset: number, _state: ScrollState) => {
        this.viewModel.syncRightListScrollToLeftList(offset);
        return { offsetRemain: offset };
      })
      // [StartExclude RightListTag]
      .cachedCount(CommonConstants.LIST_VERTICAL_CACHED_COUNT)
      .scrollBar(BarState.Off)
      .edgeEffect(EdgeEffect.None)
      .listDirection(Axis.Vertical)
      .sticky(StickyStyle.Header)
      .width(this.viewModel.horizontalContentWidth)
      .height('100%')
      .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
      .clip(false)
      // [EndExclude RightListTag]
      // [EndExclude RightScrollTag]
    }
    // [StartExclude RightListTag]
    // [StartExclude RightScrollTag]
    .scrollable(ScrollDirection.Horizontal)
    .scrollBar(BarState.Off)
    .edgeEffect(EdgeEffect.None)
    .clipContent(ContentClipMode.SAFE_AREA)
    .width(`calc(100% - ${this.config.layoutConfig.leftListWidth}vp)`)
    .height('100%')
    .layoutWeight(1)
    // [EndExclude RightScrollTag]
    .onScrollFrameBegin((offset: number, _state: ScrollState) => {
      this.viewModel.syncSubListScrollToTopList(offset);
      return { offsetRemain: offset };
    })
    // [EndExclude RightListTag]
  }
  // [End RightListTag]
  // [End RightScrollTag]

  @Builder
  RightFlatList() {
    Scroll(this.viewModel.rightAreaScroller) {
      List({ scroller: this.viewModel.rightListScroller }) {
        Repeat(this.viewModel.flatRowDataArray)
          .each((subItem: RepeatItem<TableRow>) => {
            ListItem() {
              this.RightListItemContent(subItem.item);
            }
          })
          .key((item: TableRow) => item.id)
          .virtualScroll({ reusable: false })
      }
      .onScrollFrameBegin((offset: number, _state: ScrollState) => {
        this.viewModel.syncRightListScrollToLeftList(offset);
        return { offsetRemain: offset };
      })
      .cachedCount(CommonConstants.LIST_VERTICAL_CACHED_COUNT)
      .scrollBar(BarState.Off)
      .edgeEffect(EdgeEffect.None)
      .listDirection(Axis.Vertical)
      .width(this.viewModel.horizontalContentWidth)
      .height('100%')
      .clip(false)
      .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
    }
    .scrollable(ScrollDirection.Horizontal)
    .scrollBar(BarState.Off)
    .edgeEffect(EdgeEffect.None)
    .clipContent(ContentClipMode.SAFE_AREA)
    .onScrollFrameBegin((offset: number, _state: ScrollState) => {
      this.viewModel.syncSubListScrollToTopList(offset);
      return { offsetRemain: offset };
    })
    .width(`calc(100% - ${this.config.layoutConfig.leftListWidth}vp)`)
    .height('100%')
    .layoutWeight(1)
  }

  @Builder
  RightListItemContent(subItem: TableRow) {
    RightSubList({
      itemModel: subItem,
      rowHeight: this.config.layoutConfig.subListHeight,
      itemWidth: this.config.layoutConfig.listItemWidth,
      showVerticalLine: this.getShowVerticalLine(),
      defaultCellFontColor: this.getDefaultCellFontColor(),
    }).reuse({ reuseId: () => RIGHT_TABLE_ROW_REUSE_ID })
  }

  /**
   * Top list header
   * @param title Title name
   */
  @Builder
  TopListHeader(title: ResourceStr) {
    Text(title)
      .fontColor(this.config.textStyleConfig?.topListHeaderFontColor ?? DEFAULT_TOP_LIST_HEADER_FONT_COLOR)
      .fontSize(this.config.textStyleConfig?.topListHeaderFontSize ?? $r('sys.float.Body_L'))
      .fontWeight(this.config.textStyleConfig?.topListHeaderFontWeight ?? FontWeight.Bold)
      .textAlign(TextAlign.Center)
      .height('100%')
      .width(this.config.layoutConfig.leftListWidth)
      .border({
        width: { right: this.getShowVerticalLine() ? CommonConstants.LINE_STROKE_WIDTH : 0 },
        color: $r('sys.color.comp_divider')
      })
  }

  /**
   * Bottom left vertical scroll list header
   * @param title Title name
   */
  @Builder
  LeftGroupHeader(title: string) {
    Text(title)
      .fontWeight(FontWeight.Bold)
      .height(this.config.layoutConfig.groupHeaderHeight ?? CommonConstants.DEFAULT_GROUP_HEADER_HEIGHT)
      .textAlign(TextAlign.Start)
      .width('100%')
      .backgroundColor($r('app.color.list_header_background'))
      .fontColor($r('sys.color.font_primary'))
      .fontSize($r('sys.float.Body_L'))
      .padding({ left: $r('sys.float.padding_level8') })
  }

  /**
   * Bottom right vertical scroll header
   * @param index Index value
   */
  @Builder
  RightGroupHeader() {
    Text('')
      .fontWeight(FontWeight.Medium)
      .height(this.config.layoutConfig.groupHeaderHeight ?? CommonConstants.DEFAULT_GROUP_HEADER_HEIGHT)
      .textAlign(TextAlign.End)
      .backgroundColor($r('app.color.list_header_background'))
      .width(this.viewModel.horizontalContentWidth)
      .fontColor($r('sys.color.font_primary'))
      .fontSize($r('sys.float.Body_M'))
      .padding({ right: $r('sys.float.padding_level8') })
  }
  // [EndExclude DualScrollTable]
}
// [End DualScrollTable]