/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
 * 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 { PromptAction } from '@kit.ArkUI';
import {
  DefaultSettingGroupModel,
  GroupType,
  SettingGroupLayout,
  SettingGroupModel,
} from '../model/SettingGroupModel'
import { ItemPos, SettingDialogModel, SettingItemModel } from '../model/SettingItemModel';
import { DataVerify } from '../common/DataVerify';
import { SettingItemStandard } from './SettingItemStandard';
import { BaseDataSource } from '../model/BaseDataSource';
import { OrderedDataSource } from '../model/OrderedDataSource';
import { DynamicDataSource } from '../model/DynamicDataSource';
import { SettingGroupEventHandler, SettingGroupVM } from './SettingGroupVM';
import { LogHelper } from '../common/LogHelper';
import { PageConfig } from '../common/PageConfig';
import { settingDialog } from './SettingDialog';
import { SettingSheetPageContext } from '../model/SettingPageModel';

const TAG: string = 'SettingGroup';

@Component
export struct SettingGroup {
  groupInfo: SettingGroupModel = DefaultSettingGroupModel.get();
  compId: string = '';
  fixed: boolean = false;
  pageCached: boolean = false;
  layout?: SettingGroupLayout;
  sheetPageCtx?: SettingSheetPageContext;
  private dialogId: number = 0;
  private isCircleScreen: boolean = PageConfig.getInstance().isCircleScreen();
  @State dataSource: BaseDataSource<SettingItemModel> = [];
  @State groupVM: SettingGroupVM = new SettingGroupVM();
  private eventHandler: SettingGroupEventHandler = new SettingGroupEventHandler(this.groupVM);
  private promptAction: PromptAction = this.getUIContext().getPromptAction();

  private closeDialog(item: SettingItemModel): void {
    if (this.dialogId === 0) {
      LogHelper.info(TAG, `dialog has been closed, group: ${this.compId}`);
      return;
    }

    LogHelper.info(TAG, `close dialog , group: ${this.compId}, dialogId: ${this.dialogId}`);
    try {
      this.promptAction.closeCustomDialog(this.dialogId);
      this.dialogId = 0;
    } catch (error) {
      LogHelper.error(TAG, `closeCustomDialog failed, dialogId: ${this.dialogId}, error: ${error?.message}`);
    }
  }

  private openDialog(item: SettingItemModel, dialog: SettingDialogModel): void {
    // Close existing dialog first if dialog exists.
    this.closeDialog(item);
    let dialogLayout = PageConfig.getInstance().getDialogStyle(dialog);
    this.promptAction.openCustomDialog({
      builder: settingDialog.bind(this, item, dialog, () => {
        this.closeDialog(item);
      }),
      width: dialogLayout.width,
      height: dialogLayout.height,
      backgroundColor: dialogLayout.backgroundColor,
      cornerRadius: dialogLayout.cornerRadius,
      alignment: dialogLayout.alignment,
      autoCancel: dialogLayout.autoCancel,
      maskColor: dialogLayout.maskColor,
      showInSubWindow: dialog?.showInSubWindow ?? false,
      onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
        LogHelper.info(TAG, `dialog dismiss, group ${this.compId}`);
        if (dialog?.onWillDismiss) {
          dialog.onWillDismiss();
        }
        dismissDialogAction.dismiss();
        this.dialogId = 0;
      },
    }).then((dialogId: number) => {
      LogHelper.info(TAG, `dialog opened, group ${this.compId} dialogId: ${dialogId}`);
      this.dialogId = dialogId;
    }).catch((reason: Error) => {
      LogHelper.error(TAG, `open dialog failed, group: ${this.compId}, reason: ${reason.message}`);
    });
  }

  private createDataSource(): BaseDataSource<SettingItemModel> {
    if (this.groupInfo.type === GroupType.GROUP_TYPE_DYNAMIC_LAZY) {
      return new OrderedDataSource();
    }
    return new DynamicDataSource();
  }

  private getItems(): SettingItemModel[] | BaseDataSource<SettingItemModel> {
    if (this.fixed) {
      return this.groupInfo.items ?? [];
    } else {
      return this.dataSource;
    }
  }

  private getItemPos(index: number, itemCnt: number): number {
    if (!DataVerify.checkArray(this.getItems())) {
      return 0;
    }

    let itemPos: number = 0;
    if (index === 0) {
      itemPos |= ItemPos.ITEM_POS_START;
    }
    if (index > 0 && index < itemCnt - 1) {
      itemPos |= ItemPos.ITEM_POS_CENTER;
    }
    if (index === itemCnt - 1) {
      itemPos |= ItemPos.ITEM_POS_END;
    }

    return itemPos;
  }

  private initTabIndex(item: SettingItemModel, index: number): SettingItemModel {
    item.tabIndex = this.groupInfo.tabIndex;
    return item;
  }

  @Builder groupItemBuilder(item: SettingItemModel, index: number): void {
    SettingItemStandard({
      itemInfo: this.initTabIndex(item, index),
      itemPos: this.getItemPos(index, this.getItems().length),
      compId: `${this.compId}.${item.id}`,
      parentId: this.compId,
      sheetPageCtx: this.sheetPageCtx ?? undefined,
      isVisible: item.visible ?? true,
      openDialog: (item: SettingItemModel, dialog: SettingDialogModel) => {
        this.openDialog(item, dialog);
      },
      closeDialog: () => {
        this.closeDialog(item);
      }
    });
  }

  @Styles groupCommon() {
    .id(this.compId)
    .width('100%')
    .backgroundColor(this.layout?.backgroupColor)
    .borderRadius(this.layout?.borderRadius)
    .padding(this.isCircleScreen ? undefined : this.layout?.padding)
    .margin(this.layout?.margin)
    .visibility((this.groupVM.visible && this.getItems().length > 0) ? Visibility.Visible : Visibility.None)
  }

  @Builder fixedGroupBuilder(): void {
    Column() {
      ForEach(this.groupInfo.items, (item: SettingItemModel, index: number) => {
        this.groupItemBuilder(item, index)
      }, (item: SettingItemModel) => item?.id + '_' + item?.subId)
    }
    .groupCommon()
  }

  @Builder listGroupBuilder(): void {
    ListItemGroup() {
      ForEach(this.getItems(), (item: SettingItemModel, index: number) => {
        ListItem() {
          this.groupItemBuilder(item, index)
        }
      }, (item: SettingItemModel, index: number) => item.id + '_' + item?.subId)
    }
    .groupCommon()
    .divider(PageConfig.getInstance().getGroupDividerStyle(this.layout?.dividerStyle))
  }

  @Builder lazyGroupBuilder(): void {
    ListItemGroup() {
      LazyForEach(this.getItems() as OrderedDataSource, (item: SettingItemModel, index: number) => {
        ListItem() {
          this.groupItemBuilder(item, index)
        }
      }, ((item: SettingItemModel) => item?.id + '_' + item?.subId))
    }
    .groupCommon()
    .divider(PageConfig.getInstance().getGroupDividerStyle(this.layout?.dividerStyle))
  }

  aboutToAppear(): void {
    LogHelper.info(TAG, `setting group ${this.compId} appear.`);
    this.dataSource = this.createDataSource();
    this.eventHandler.init(this.groupInfo, this.compId, (this.groupInfo.type === GroupType.GROUP_TYPE_STANDARD) ?
      (this.dataSource as DynamicDataSource) : undefined);

    // 标准类型,将配置模型转换为VM
    if (this.groupInfo.type === GroupType.GROUP_TYPE_STANDARD) {
      this.dataSource.push(...(this.groupInfo.items ?? []));
    }

    if (this.groupInfo.compControl) {
      this.groupInfo.compControl.init({
        compId: this.compId,
        component: this.groupInfo,
        dataSource: this.getItems()
      });
    }
  }

  aboutToDisappear(): void {
    LogHelper.info(TAG, `setting group ${this.compId} disappear.`);
    this.eventHandler.destroy();

    if (this.dialogId !== 0) {
      this.promptAction.closeCustomDialog(this.dialogId);
      this.dialogId = 0;
    }

    if (this.groupInfo.compControl) {
      this.groupInfo.compControl.destroy();
    }
  }

  build() {
    if (!this.groupInfo.needHide) {
      if (this.groupInfo.type === GroupType.GROUP_TYPE_STANDARD) {
        if (this.groupInfo.items && this.groupInfo.items.length > 0) {
          if (this.fixed) {
            this.fixedGroupBuilder()
          } else {
            this.listGroupBuilder()
          }
        }
      } else if (this.groupInfo.type === GroupType.GROUP_TYPE_DYNAMIC) {
        this.listGroupBuilder()
      } else if (this.groupInfo.type === GroupType.GROUP_TYPE_DYNAMIC_LAZY) {
        this.lazyGroupBuilder()
      }
    }
  }
}