/*
 * 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 { bundleManager, installer } from '@kit.AbilityKit';
import Want from '@ohos.app.ability.Want';
import { LogUtil } from '@ohos/settings.common/src/main/ets/utils/LogUtil';
import { AccountUtil } from '@ohos/settings.common/src/main/ets/utils/AccountUtil';
import {
  CompCtrlParam,
  ComponentControl,
  SettingBaseModel
} from '@ohos/settings.common/src/main/ets/framework/model/SettingBaseModel';
import { GroupType, } from '@ohos/settings.common/src/main/ets/framework/model/SettingGroupModel';
import { SettingPageModel } from '@ohos/settings.common/src/main/ets/framework/model/SettingPageModel';
import { PageRouter } from '@ohos/settings.common/src/main/ets/framework/common/PageRouter';
import { CheckEmptyUtils } from '@ohos/settings.common/src/main/ets/utils/CheckEmptyUtils';
import { PushParam } from '@ohos/settings.common/src/main/ets/core/controller/Controller';
import { EventBus } from '@ohos/settings.common/src/main/ets/framework/common/EventBus';
import { DynamicGroupDataSource } from '@ohos/settings.common/src/main/ets/framework/model/DynamicGroupDataSource';
import { ResourceUtil } from '@ohos/settings.common/src/main/ets/utils/ResourceUtil';
import { HiSysEventUtil } from '@ohos/settings.common/src/main/ets/systemEvent/HiSysEventUtil';
import {
  HiSysApplicationsAndServicesEventGroup
} from '@ohos/settings.common/src/main/ets/systemEvent/BehaviorEventConsts';
import {
  notifyCompStateChange,
  SettingBaseState,
  SettingContentState,
  SettingStateType
} from '@ohos/settings.common/src/main/ets/framework/model/SettingStateModel';
import { ExternalMenuPreloadManager } from '@ohos/settings.common/src/main/ets/externalmenu/ExternalMenuPreloadManager';
import { AppItemHeaderComponent } from '../components/AppItemHeaderComponent';
import { PermissionMenuComponent } from '../components/PermissionMenuComponent';
import { SettingAppGroupModel } from '../model/SettingAppItemModel';
import { AppNetworkController } from './AppNetworkController';
import { AppDetailActionComponent } from '../components/AppDetailActionComponent';
import { AppAllowAccessController } from './AppAllowAccessController';
import { DefaultBrowserItemController } from './DefaultBrowserItemController';
import { DefaultEmailItemController } from './DefaultEmailItemController';
import { AppListLoader } from '../AppListLoader';
import { AppEntry } from '../AppModel';
import { AppUtils } from '../AppUtils';
import { AppManager } from '../util/AppManager';

const TAG = 'AppDetailController: '

@Builder
function appDetailActionBuilder(param: object): void {
  AppDetailActionComponent({ appItem: param as SettingAppGroupModel });
}

@Builder
function permissionMenuBuilder(param: object): void {
  PermissionMenuComponent({ appItem: param as SettingAppGroupModel });
}

@Builder
function appItemHeaderBuilder(param: object): void {
  AppItemHeaderComponent({ appItem: param as SettingAppGroupModel });
}

export class AppDetailController implements ComponentControl {
  private params: PushParam = new PushParam();
  private comp: SettingPageModel | null = null;
  private appListLoader: AppListLoader = AppListLoader.getInstance();
  private entry: AppEntry | null = null;
  private bundleName: string = '';
  private appIndex: number = 0;
  private label: string = '';
  private isMoreApp: boolean = false;
  private dataSource: DynamicGroupDataSource = new DynamicGroupDataSource();

  init(compParam: CompCtrlParam): void {
    if (!compParam || !compParam.compId) {
      LogUtil.error(`${TAG} init fail, compParam is invalid`);
      return;
    }
    LogUtil.info(`${TAG} init begin: ${compParam.compId}`);
    this.params = compParam.param as PushParam;
    this.comp = compParam.component as SettingPageModel;
    this.dataSource = compParam.dataSource as DynamicGroupDataSource;
    if (!this.params) {
      LogUtil.info(`${TAG} init fail, init params is undefined`);
      return;
    }
    this.initBundleName();
    this.processExternal(this.params);
    LogUtil.info(`${TAG} init entry ${this.entry?.name}`);
    this.label = this.entry?.label as string;
    this.reportEvent();
    // ExternalMenuPreloadManager.getInstance().preloadUIExtensionAbility('SettingsPermissionAbility', getContext());
    HiSysEventUtil.reportDefaultBehaviorEventByUE(HiSysApplicationsAndServicesEventGroup.ENTER_APPLICATION_INFO_ENTRY,
      this.bundleName);
    LogUtil.info(`${TAG} init success`);
  }

  onPageShow(component: SettingBaseModel): void {
    LogUtil.info(`${TAG} onPageShow.`);
    EventBus.getInstance().emit('EVENT_ID_APP_DETAIL_PAGE_SHOW');
    this.updateTitle(this.entry?.label as string);
    // 如果该应用已经被卸载或者分身应用已被删除,则直接返回
    this.popPage();
  }

  onPageHide(component: SettingBaseModel): void {
    LogUtil.info(`${TAG} onPageHide.`);
  }

  private popPage(): void {
    if (!this.entry) {
      return;
    }
    if (!AppUtils.isBundleExist(this.entry?.name, this.entry?.appIndex)) {
      LogUtil.error(`${TAG} app not exist: ${this.entry?.name}, appIndex: ${this.entry?.appIndex}`);
      PageRouter.pop('Setting');
    }
  }

  private reportEvent() {
    let eventName: string = this.entry?.appInfo?.bundleType ?
      HiSysApplicationsAndServicesEventGroup.ENTER_META_MANAGE_PAGE :
      HiSysApplicationsAndServicesEventGroup.ENTER_NOTIFY_MANAGE_PAGE;
    HiSysEventUtil.reportDefaultBehaviorEventByUE(eventName, this.bundleName);
  }

  private initBundleName() {
    this.bundleName = this.params.config as string;
    if ((typeof this.bundleName !== 'string') || CheckEmptyUtils.checkStrIsEmpty(this.bundleName)) {
      this.bundleName = AppStorage.get<Want>('wantParams')?.parameters?.settingsParamBundleName as string ?? '';
    }
    this.appIndex = this.params.appIndex ?? 0;
    this.isMoreApp = this.params.itemName === 'MoreApp';
  }

  private async processExternal(inputPushParam: PushParam): Promise<void> {
    LogUtil.info(`${TAG} processExternal startReason: ${inputPushParam.startReason}`);
    if (inputPushParam.startReason === 'from_external') {
      let appIndexInWant: Object | undefined = AppStorage.get<Want>('wantParams')?.parameters?.appIndex;
      if (CheckEmptyUtils.isEmpty(appIndexInWant) || typeof appIndexInWant !== 'number') {
        // 未从wantParams 中取到,则去getAppCloneIdentity接口获取AppCloneIdentity,获取appIndex
        appIndexInWant = await this.getAppIndexInCaller();
        LogUtil.info(`${TAG} external appIndexInWant ${appIndexInWant}`);
      }
      this.appIndex = Number.isNaN(appIndexInWant as number) ? 0 : (appIndexInWant as number);
    }
    await this.initEntry();
    this.label = this.entry?.label as string;
    LogUtil.info(`${TAG} processExternal end, ${this.entry?.name}, ${this.appIndex}`);
    this.checkUninstallUpdate();
    this.addGroups();
  }

  private async checkUninstallUpdate(): Promise<void> {
    if (!this.entry) {
      LogUtil.showWarn(TAG, 'entry invalid');
      return;
    }
    let isCurrentMain: boolean = await AccountUtil.isCurrentAdmin();
    LogUtil.info(`${TAG} isCurrentMain: ${isCurrentMain}`);
    const bundleName = this.entry?.name || '';
    let isAppPreUpdated: boolean = AppManager.getInstance()
      .isAppPreUpdated(bundleName, AppListLoader.getInstance().getAppType(this.entry));
    LogUtil.info(`${TAG} isAppPreUpdated: ${isAppPreUpdated}`);
    let isRemovable = this.entry?.removable as boolean;
    LogUtil.info(`${TAG} isRemovable: ${isRemovable}`);
    if (!isRemovable && isCurrentMain && isAppPreUpdated) {
      LogUtil.info(`${TAG} show more_options`);
      this.comp?.menus?.push(
        {
          icon: $r('app.media.ic_public_more'),
          style: { accessibilityText: $r('app.string.more_options') },
          bindMenu: [
            {
              value: $r('app.string.app_info_uninstall_update'),
              action: () => {
                LogUtil.info(`${TAG} show uninstall update dialog`);
                EventBus.getInstance().emit('showUninstallUpdateDialog');
              },
            },
          ],
        }
      );
    }
  }

  private async initEntry(): Promise<void> {
    if (this.isMoreApp) {
      this.entry = await this.appListLoader.createAppEntryByName(this.bundleName, this.appIndex);
    } else {
      this.entry = this.appListLoader.getAppEntry(this.bundleName, this.appIndex) as AppEntry;
      if (!this.entry) {
        this.entry = await this.appListLoader.createAndCache(this.bundleName, this.appIndex);
      }
    }
    if (!this.entry) {
      LogUtil.error(`${TAG} initEntry fail`);
      PageRouter.pop('Setting');
    }
  }

  private async getAppIndexInCaller(): Promise<number> {
    let params = AppStorage.get<Want>('wantParams')?.parameters as Record<string, string>;
    let caller: string = '';
    Object.entries(params)?.forEach(
      (value: [key: string, value: string], index: number) => {
        if (value[0] === 'ohos.aafwk.param.callerUid') {
          caller = value[1];
        }
      }
    );
    LogUtil.info(`${TAG} getAppIndexInCaller, callerUid: ${Number(caller)}`);

    let appIndex: number = 0;
    try {
      const appCloneIdentity = await bundleManager.getAppCloneIdentity(Number(caller));
      LogUtil.info(`${TAG} getAppIndexInCaller, bundleName: ${appCloneIdentity?.bundleName} appIndex:${appCloneIdentity?.appIndex}`);
      appIndex = appCloneIdentity.appIndex;
    } catch (error) {
      LogUtil.error(`${TAG} getAppCloneIdentity failed, message: ${error?.message}, code: ${error?.code}`);
    }
    LogUtil.info(`${TAG} getAppIndexInCaller, appIndex: ${appIndex}`);
    return appIndex;
  }

  private getNotificationHeader(label: string): string {
    return ResourceUtil.getFormatStringSync($r('app.string.app_info_allow_access'), label as string);
  }

  private updateTitle(label: string) {
    LogUtil.info(`${TAG} updateTitle: ${label}`);
    notifyCompStateChange('Setting.AppDetail',
      new Map<SettingStateType, SettingBaseState>([[SettingStateType.STATE_TYPE_PAGE_TITLE,
        { content: label } as SettingContentState]]
      ));
  }

  private async addGroups(): Promise<void> {
    let isAppEnable: boolean = await AppManager.getInstance().getIsApplicationEnabled(this.bundleName, this.appIndex,
      AppListLoader.getInstance().getAppType(this.entry));
    let groups = [
      {
        id: 'AppInfoHeaderGroup',
        type: GroupType.GROUP_TYPE_CUSTOM,
        builder: wrapBuilder(appItemHeaderBuilder),
        icon: this.entry?.icon,
        versionName: this.entry?.versionName,
        label: this.entry?.label,
        name: this.entry?.name,
        entry: this.entry
      } as SettingAppGroupModel,
      {
        id: 'AppDetailActionGroup',
        type: GroupType.GROUP_TYPE_CUSTOM,
        builder: wrapBuilder(appDetailActionBuilder),
        bundleName: this.bundleName,
        appIndex: this.appIndex,
        entry: this.entry
      } as SettingAppGroupModel,
      {
        id: 'AppAllowAccessGroup',
        type: GroupType.GROUP_TYPE_DYNAMIC,
        header: {
          id: 'AppAllowAccessGroupHeader',
          content: isAppEnable ? this.getNotificationHeader(this.label) : '',
        },
        compControl: new AppAllowAccessController(),
        layout: {
          dividerStyle: {
            startMargin: 8,
            endMargin: 8
         },
        },
        entry: this.entry,
        visible: isAppEnable
      } as SettingAppGroupModel,
      {
        id: 'AppNetworkGroup',
        type: GroupType.GROUP_TYPE_DYNAMIC,
        visible: isAppEnable,
        compControl: new AppNetworkController(),
        entry: this.entry
      } as SettingAppGroupModel,
      {
        id: 'DefaultBrowserGroup',
        type: GroupType.GROUP_TYPE_DYNAMIC,
        visible: isAppEnable,
        compControl: new DefaultBrowserItemController(),
        entry: this.entry,
      } as SettingAppGroupModel,
      {
        id: 'DefaultEmailGroup',
        type: GroupType.GROUP_TYPE_DYNAMIC,
        visible: isAppEnable,
        compControl: new DefaultEmailItemController(),
        entry: this.entry,
      } as SettingAppGroupModel,
      // {
      //   id: 'PermissionGroup',
      //   type: GroupType.GROUP_TYPE_CUSTOM,
      //   builder: wrapBuilder(permissionMenuBuilder),
      //   bundleName: this.bundleName,
      //   appIndex: this.appIndex,
      //   entry: this.entry,
      //   visible: isAppEnable
      // } as SettingAppGroupModel,
    ];
    LogUtil.info(`${TAG} addGroups pushData, ${groups.length}, ${isAppEnable}`);
    this.dataSource.pushData(...groups);
    this.updateTitle(this.entry?.label as string);
  }

  destroy(): void {
    LogUtil.showInfo(TAG, 'onDestroy');
  }
}