/*
 * Copyright (c) 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 { display, typeNode } from '@kit.ArkUI';
import { type NodeItem, RecyclerView, WaterFlowManager } from '@hadss/scroll_components';
import { CommonConstants } from '../common/constants/CommonConstants';
import { Logger } from '../common/util/Logger';
import { isChinese } from '../model/mock';
import { BusinessError } from '@kit.BasicServicesKit';

interface Params3 {
  item: number
}

class MyWaterFlowManager extends WaterFlowManager {
  onWillCreateItem(index: number, data: Params3): NodeItem {
    let nodeItem: NodeItem = this.dequeueReusableNodeByType('StickyBlogItemContainer');
    nodeItem?.setData({ item: data });
    return nodeItem;
  }
}

@Component
struct StickyFlowItem {
  @State item: number = 0;

  // In reusable components, you must use aboutToReuse to update data, just like native recycling.
  aboutToReuse(params: ESObject): void {
    this.item = params.item;
  }

  build() {
    if (this.item !== 1) {
      RelativeContainer() {
        Image($rawfile(`sections/${this.item % 4}.jpg`))
          .objectFit(ImageFit.Cover)
          .width(CommonConstants.FULL_WIDTH)
          .layoutWeight(1)
          .borderRadius($r('app.float.sections_item_radius'))
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top },
            bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
            left: { anchor: '__container__', align: HorizontalAlign.Start },
            right: { anchor: '__container__', align: HorizontalAlign.End }
          })
          .id('image');

        Stack() {
        }
        .linearGradient({
          angle: 0,
          colors: [[$r('app.color.linearGradient_first_color'), 0.0],
            [$r('app.color.linearGradient_last_color'), 1.0]]
        })
        .width(CommonConstants.FULL_WIDTH)
        .height($r('app.float.sections_item_blur_height'))
        .borderRadius($r('app.float.sections_item_radius'))
        .hitTestBehavior(HitTestMode.None)
        .alignRules({
          bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
          left: { anchor: '__container__', align: HorizontalAlign.Start },
          right: { anchor: '__container__', align: HorizontalAlign.End }
        })
        .id('mask');

        Text($r('app.string.want_to_eat'))
          .fontSize($r('app.float.sections_item_text_size'))
          .fontColor(Color.White)
          .alignRules({
            bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
          .margin({ bottom: $r('app.float.sections_item_center_text_margin_bottom') })
          .id('text');
      };
    }
  }
}

@Builder
function stickyBlogItemContainerBuilder(param: Params3): void {
  StickyFlowItem({ item: param.item });
}

@Entry
@Component
struct StickyWaterFlowPage {
  waterFlowView: MyWaterFlowManager =
    new MyWaterFlowManager({ defaultNodeItem: 'StickyBlogItemContainer', context: this.getUIContext() });
  @State arr: number[] = CommonConstants.ARR;
  @State colors: number[] = CommonConstants.COLORS;
  @State scrollOffset: number = 0;
  @State minSize: number = 80;
  @State maxSize: number = 180;
  // [Start Section]
  @State sections: WaterFlowSections = new WaterFlowSections();
  // [End Section]
  scroller: Scroller = new Scroller();
  dataCount: number = 100;
  private itemWidthArray: number[] = [];
  private itemHeightArray: number[] = [];
  // [Start Section]
  oneColumnSection: SectionOptions = {
    itemsCount: 3,
    crossCount: 1,
    columnsGap: 5,
    rowsGap: 10,
    margin: {
      top: 8,
      left: 0,
      bottom: 8,
      right: 0
    },
    onGetItemMainSizeByIndex: (index: number) => {
      if (index === 1) {
        return 100;
      } else {
        return 200;
      }
    }
  };
  twoColumnSection: SectionOptions = {
    itemsCount: 2,
    crossCount: 2,
    onGetItemMainSizeByIndex: () => {
      return 250;
    }
  };
  // [End Section]

  getResourceStringArray(resource: Resource): Array<string> {
    let result: string[] = [];
    try {
      result = this.getUIContext().getHostContext()?.resourceManager.getStringArrayValueSync(resource.id) as string[];
    } catch (e) {
      Logger.error(`[getResourceString]getStringSync failed, error:${JSON.stringify(e)}.`);
    }
    return result;
  }

  getSize(): number {
    let ret = Math.floor(Math.random() * this.maxSize);
    return (ret > this.minSize ? ret : this.minSize);
  }

  setItemSizeArray(): void {
    for (let i = 0; i < 100; i++) {
      this.itemWidthArray.push(this.getSize());
      this.itemHeightArray.push(this.getSize());
    }
  }

  aboutToAppear() {
    this.setItemSizeArray();
    this.initView();

    let dataArray: number[] = [];
    for (let i = 0; i < 100; i++) {
      dataArray.push(i);
    }
    this.waterFlowView.setDataSource(dataArray);
    this.waterFlowView.registerNodeItem('StickyBlogItemContainer', wrapBuilder(stickyBlogItemContainerBuilder));
    this.waterFlowView.preCreate('StickyBlogItemContainer', 30);
  }

  // [Start Section_2]
  initView(): void {
    let sectionOptions: SectionOptions[] = [];
    let count = 0;
    let oneOrTwo = 0;
    while (count < this.dataCount) {
      if (oneOrTwo++ % 2 === 0) {
        sectionOptions.push(this.oneColumnSection);
        count += this.oneColumnSection.itemsCount;
      } else {
        sectionOptions.push(this.twoColumnSection);
        count += this.twoColumnSection.itemsCount;
      }
    }
    this.sections.splice(-1, 0, sectionOptions);
    // [Start Stick]
    // [Start Section_3]
    this.waterFlowView.setViewStyle({ scroller: this.scroller, sections: this.sections })
      // [StartExclude Stick]
      // [StartExclude Section_3]
      // [StartExclude Section_2]
      .columnsTemplate('1fr 1fr')
      .columnsGap(CommonConstants.COLUMNS_GAP)
      .rowsGap(CommonConstants.ROWS_GAP)
      .width(CommonConstants.FULL_WIDTH)
      .height(CommonConstants.FULL_HEIGHT)
      .edgeEffect(EdgeEffect.Spring)
      .layoutWeight(1)
      .scrollBar(BarState.Off)
      .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
        // [EndExclude Section_3]
      .onScrollIndex((_first: number, last: number) => {
        if (last + 20 >= this.waterFlowView.nodeAdapter.totalNodeCount) {
          let dataArray: number[] = [];
          for (let i = 0; i < 100; i++) {
            dataArray.push(i);
          }
          // update data when the page is scrolling.
          this.waterFlowView.nodeAdapter.pushData(dataArray);
          let newSection: SectionOptions = {
            itemsCount: 100,
            crossCount: 2,
            onGetItemMainSizeByIndex: () => {
              return 100;
            }
          };
          // update section
          this.sections.push(newSection);
          this.waterFlowView.setViewStyle({
            scroller: this.scroller, // it's very important to do initialize that makes section update.
            sections: this.sections,
          });
        }
      })
      // [EndExclude Stick]
      // [StartExclude Section_3]
      .onWillScroll((offset: number) => {
        // Dynamically get the offset position of a waterfall flow
        this.scrollOffset = this.scroller.currentOffset().yOffset + offset;
      });
      // [EndExclude Section_3]
      // [EndExclude Section_2]
    // [End Section_3]
    // [End Stick]

    // [StartExclude Section_2]
    this.waterFlowView.setItemViewStyle((flowItem, _index, item: number) => {
      flowItem().width(CommonConstants.FULL_WIDTH)
        .height(this.itemHeightArray[item % 100])
        .backgroundColor(Color.White);
    });
    // [EndExclude Section_2]
  }
  // [End Section_2]
  // [Start Stick]
  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      RecyclerView({
        viewManager: this.waterFlowView
      });
      Stack() {
        // [StartExclude Stick]
        Column() {
          Scroll() {
            Row({ space: 0 }) {
              ForEach(isChinese() ? this.getResourceStringArray($r('app.strarray.tab_titles')) : this.getResourceStringArray($r('app.strarray.tab_titles_en')), (item: string) => {
                Row() {
                  Text(item)
                    .constraintSize({ minWidth: $r('app.float.tab_height') })
                    .textAlign(TextAlign.Center)
                    .fontSize($r('app.float.tab_font_size'))
                    .fontColor(Color.Black)
                    .padding({
                      left: $r('app.float.tab_text_padding_left'),
                      right: $r('app.float.tab_text_padding_right')
                    })
                    .height(CommonConstants.FULL_HEIGHT)
                    .backgroundColor($r('app.color.sections_tab_color_normal'))
                    .borderRadius($r('app.float.sections_tab_radius'));
                }
                .padding({
                  top: 0,
                  bottom: 0,
                  left: 0,
                  right: $r('app.float.tab_padding_right')
                })
                .justifyContent(FlexAlign.Center)
                .height($r('app.float.sections_sticky_tab_height'))
                .align(Alignment.Center);
              }, (item: string) => item.toString());
            };
          }
          .width(CommonConstants.FULL_WIDTH)
          .scrollBar(BarState.Off)
          .scrollable(ScrollDirection.Horizontal)
          .backgroundColor(Color.White)
          .padding({ top: $r('app.float.sections_margin') });

          Scroll() {
            Row() {
              Select([{ value: $r('app.string.distance') },
                { value: $r('app.string.less_1km') },
                { value: $r('app.string.less_5km') },
                { value: $r('app.string.more_5km') }])
                .selected(1)
                .value($r('app.string.distance'))
                .font({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .fontColor(Color.Black)
                .selectedOptionFont({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .optionFont({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .backgroundColor($r('app.color.sections_tab_color_normal'));
              Select([{ value: $r('app.string.classify') },
                { value: $r('app.string.food') },
                { value: $r('app.string.leisure') },
                { value: $r('app.string.entertainment') }])
                .selected(1)
                .value($r('app.string.classify'))
                .font({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .fontColor(Color.Black)
                .selectedOptionFont({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .optionFont({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .backgroundColor($r('app.color.sections_tab_color_normal'))
                .margin({ left: $r('app.float.sections_margin') });
              Select([{ value: $r('app.string.sort') },
                { value: $r('app.string.one') },
                { value: $r('app.string.two') },
                { value: $r('app.string.three') }])
                .selected(1)
                .value($r('app.string.sort'))
                .font({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .fontColor(Color.Black)
                .selectedOptionFont({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .optionFont({
                  size: $r('app.float.sections_sticky_select_text_size'),
                  family: 'serif',
                  style: FontStyle.Normal
                })
                .backgroundColor($r('app.color.sections_tab_color_normal'))
                .margin({ left: $r('app.float.sections_margin') });
            };
          }
          .width(CommonConstants.FULL_WIDTH)
          .scrollBar(BarState.Off)
          .scrollable(ScrollDirection.Horizontal)
          .backgroundColor(Color.White)
          .padding({ top: $r('app.float.sections_margin') });
        }.alignItems(HorizontalAlign.Start);
        // [EndExclude Stick]
      }
      .width(CommonConstants.FULL_WIDTH)
      .height(100)
      .padding({ left: CommonConstants.PADDING, right: CommonConstants.PADDING })
      .backgroundColor(Color.White)
      .hitTestBehavior(HitTestMode.Transparent)
      // Set the sticky component's offset.
      .position({ x: 0, y: this.scrollOffset >= 220 ? 0 : 220 - this.scrollOffset });
    };
  }
  // [End Stick]
}