/*
 * Copyright (c) Huawei Device 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 { NotificationBase, NotificationDataManager, threadCall,} from '@ohos/systemuicommon/newTsIndex';
import process from '@ohos.process';
import { notificationConfigManager } from '../manager/NotificationConfigManager';
import { notificationManager } from '@kit.NotificationKit';
import { commonEventManager } from '@kit.BasicServicesKit';
import {
  ClickNotificationErrorCode,
  ClickNotificationMaintenance
} from '@ohos/systemuicommon/src/main/ets/maintenance/ClickNotificationMaintenance';
import { AnimateToScheduleUtils, LogDomain, LogHelper } from '@ohos/basicutils/src/main/ets/TsIndex';
import { ExtAppConstants, WindowConstants } from '@ohos/commonconstants/src/main/ets/TsIndex';
import lazy { SCBScreenSessionManager, SCBSystemSceneSession, SCBSceneSessionManager,
  StartAbilityUtil } from '@ohos/windowscene/src/main/ets/TsIndex';
import { DefaultPanelZIndex } from '@ohos/systemuicommon/src/main/ets/base/common/info/DefaultPanelZIndex';
import sceneSessionManager from '@ohos.sceneSessionManager';
import settings from '@ohos.settings';
import { FingerprintEvent } from '@ohos.multimodalInput.shortKey';
import { GlobalContext, obtainLocalEvent, sEventManager, EventConstants } from '@ohos/frameworkwrapper';
import lazy { OuterAppManager } from '@ohos/launchercommon/src/main/ets/manager/OuterAppManager';
import lazy { AppBundleInfo, AppInfo } from '@ohos/launchercommon/src/main/ets/bean/OuterAppNameList';
import { ArkUIAdapter } from '@ohos/systemuicommon/src/main/ets/utils/ArkUIAdapter';
import { StatusBarEventType } from '@ohos/systemuicommon/src/main/ets/event/StatusBarEvent';
import { NotificationConstants } from '../common/NotificationConstants';
import { bundleManager } from '@kit.AbilityKit';
import { MetaServiceConnect } from '@ohos/systemuicommon/src/main/ets/manager/MetaServiceConnect';
// import { serviceNotification } from '@kit.PushKit';

const log = LogHelper.getLogHelper(LogDomain.NC, 'NotificationApiUtil');

/**
 * 录屏bundleName
 */
const SCREEN_RECORDE_BUNDLE_NAME = 'com.ohos.screenrecorder';

/**
 * 进程异常退出取消通知原因码
 */
const ABNORMAL_REASON_CODE = 6;

/**
 * 与底层交互的通知API工具类
 */
export class NotificationApiUtil {
  /**
   * 关闭通知开关
   * @param ntf
   */
  public static closeSwitch(ntf: NotificationBase): void {
    if (ntf.isLiveView()) {
      NotificationApiUtil.setLiveViewEnable(ntf.creatorBundleName, ntf.creatorUid, false);
    } else {
      // 关闭置顶
      if (ntf.isDisplayAtTop) {
        notificationConfigManager.setPinTopState(ntf.creatorUid, false);
      }

      // 关闭通知
      NotificationApiUtil.setNtfEnable(ntf.creatorBundleName, ntf.creatorUid, false);
    }
  }

  /**
   * 设置应用通知开关
   *
   * @param bundleName 应用包名
   * @param uid 应用uid
   * @param enable 是否开启
   */
  public static async setNtfEnable(bundleName: string, uid: number, enable: boolean): Promise<void> {
    const clickInfo = ClickNotificationMaintenance.getInfo();
    try {
      log.showInfo(`Set notification switch of ${bundleName}_${uid} to ${enable} begin`);
      await notificationManager.setNotificationEnable({
        bundle: bundleName,
        uid: uid
      }, enable);
      ClickNotificationMaintenance.reportClick(ClickNotificationErrorCode.SET_NTF_ENABLE_SUCC, clickInfo);
      log.showInfo(`Set notification switch of ${bundleName}_${uid} to ${enable} end`);
    } catch (e) {
      ClickNotificationMaintenance.reportClick(ClickNotificationErrorCode.SET_NTF_ENABLE_FAIL, clickInfo);
      log.error(`Set notification switch of ${bundleName}_${uid} to ${enable} error:`, e);
    }
  }

  /**
   * 设置应用实况窗开关
   *
   * @param bundleName 应用包名
   * @param uid 应用uid
   * @param enable 是否开启
   */
  public static async setLiveViewEnable(bundleName: string, uid: number, enable: boolean): Promise<void> {
    try {
      log.showInfo(`Set live view switch of ${bundleName}_${uid}} to ${enable} begin`);
      await notificationManager.setNotificationEnableSlot({
        bundle: bundleName,
        uid: uid
      }, notificationManager.SlotType.LIVE_VIEW, enable, true);
      log.showInfo(`Set live view switch of ${bundleName}_${uid}} to ${enable} end`);
    } catch (e) {
      log.error(`Set live view switch of ${bundleName}_${uid}} to ${enable} error:`, e);
    }
  }

  /**
   * 设置元服务通知开关
   *
   * @param bundleName 应用包名
   * @param uid 应用uid
   * @param enable 是否开启
   */
  static async setMetaServiceNotificationEnable(bundleName: string, uid: number, enable: boolean): Promise<void> {
    try {
      log.showInfo(`set meta service notification enable begin: ${bundleName}, ${uid}, ${enable}`);
      await notificationManager.setNotificationEnable({ bundle: bundleName, uid }, enable);
      // await serviceNotification.setSubscribeNotificationSetting(bundleName, { bundleName, enable });
      log.showInfo(`set meta service notification enable success: ${bundleName}, ${uid}, ${enable}`);
    } catch (err) {
      log.error(`set meta service notification enable failed: ${bundleName}`, err);
    }
  }

  /**
   * 设置未安装元服务实况开关
   *
   * @param bundleName 应用包名
   * @param uid 应用uid
   * @param enable 是否开启
   */
  static async setUnstallMetaServiceLiveEnable(bundleName: string, uid: number, enable: boolean): Promise<void> {
    await MetaServiceConnect.instance.collectMetaSerciveLiveChange('', bundleName)
  }

  /**
   * 点击删除通知
   *
   * @param ntf 通知
   */
  public static async removeNtfByClick(ntf: NotificationBase): Promise<void> {
    log.showInfo('Remove ntfList by click');
    await NotificationDataManager.instance.removeLiveView([ntf], true);
  }

  /**
   * 删除按钮移除通知
   *
   * @param ntfList 通知列表
   */
  public static async removeNtfByCancel(ntfList: NotificationBase[]): Promise<void> {
    await NotificationDataManager.instance.removeLiveView(ntfList, false);
  }

  public static async batchRemoveNtfByClick(ntfList: NotificationBase[]): Promise<void> {
    log.showInfo('Remove ntfList by click');
    await NotificationDataManager.instance.removeLiveView(ntfList, true);
  }

  /**
   * 打开通知设置(提供给子线程 跨线程调用)
   * @param bundleName
   * @param appIndex
   */
  @threadCall()
  public static openNtfSetting(bundleName: string, appIndex: number, uri: string, uid: number, isMetaService: boolean = false) {
    if (isMetaService) {
      StartAbilityUtil.startAbilityFromOther({
        bundleName: ExtAppConstants.PKG_SETTINGS,
        abilityName: ExtAppConstants.ABILITY_SETTINGS_MAIN,
        moduleName: ExtAppConstants.MODULE_PHONE_SETTINGS_SOUND,
        uri: 'systemui_notification_settings',
        parameters: {
          pushParams: {
            config: { bundleName: bundleName, isFromNc: true, appIndex, uid, isMetaService: true },
          }
        }
      });
      return;
    }
    StartAbilityUtil.startAbilityFromOther({
      bundleName: ExtAppConstants.PKG_SETTINGS,
      abilityName: ExtAppConstants.ABILITY_SETTINGS_MAIN,
      moduleName: ExtAppConstants.MODULE_PHONE_SETTINGS_SOUND,
      uri: uri,
      parameters: {
        pushParams: {
          config: {bundleName: bundleName, isFromNc: true, appIndex: appIndex, uid: uid}
        }
      }
    });
  }

  /**
   * 跳转时钟首页(提供给子线程 跨线程调用)
   */
  @threadCall()
  public static startClockMainAbility(): void {
    StartAbilityUtil.startAbilityFromOther({
      bundleName: ExtAppConstants.PKG_CLOCK,
      abilityName: ExtAppConstants.ABILITY_CLOCK,
      moduleName: ExtAppConstants.MODULE_CLOCK,
      parameters: {
        action: 'CLICK_TIME_FORM_HEADER',
        tabActive: 'ALARM_CLOCK_TAB'
      }
    });
  }

  /**
   * 跳转日历首页(提供给子线程 跨线程调用)
   */
  @threadCall()
  public static startCalendarMainAbility(): void {
    let date = new Date();
    StartAbilityUtil.startAbilityFromOther({
      bundleName: ExtAppConstants.PKG_CALENDAR,
      abilityName: ExtAppConstants.ABILITY_CALENDAR,
      moduleName: ExtAppConstants.MODULE_CALENDAR,
      parameters: {
        action: 'CLICK_MONTH_FORM_HEADER',
        tabIndex: '1',
        year: date.getFullYear(),
        month: date.getMonth(),
        day: date.getDate()
      }
    });
  }

  /**
   * 提升GC避让效率
   * @param value 0-动效开始 1-动效结束
   */
  public static raiseAnimateToGCPriority(value: number): void {
    AnimateToScheduleUtils.raiseAnimateToGCPriority(value, process.tid);
  }

  /**
   * 设置窗口旋转状态(提供给子线程 跨线程调用)
   * @param enabled
   */
  @threadCall()
  public static setRotateEnabled(enabled: boolean): void {
    const screenSession = SCBScreenSessionManager.getInstance().getMainScreenSession();
    screenSession?.setEnableRotate(enabled, WindowConstants.WINDOW_NAME_DROPDOWN);
  }

  /*
   * 打开通知设置弹窗,设置状态栏层级,状态栏层级比页面层级高,状态栏层级需降级(提供给子线程 跨线程调用)
   */
  @threadCall()
  public static setStatusBarZIndex(action: 'update' | 'reset'): void {
    try {
      const sysSessionStatusBar: SCBSystemSceneSession = SCBSceneSessionManager.getInstance()
        .getSystemSceneSessionWithSystemType(sceneSessionManager.SessionType.TYPE_STATUS_BAR);
      if (!sysSessionStatusBar) {
        log.showInfo(`failed to get sysSessionStatusBar`);
        return;
      }
      if (action === 'update') {
        sysSessionStatusBar.zIndex = DefaultPanelZIndex.PANEL_STATUS_BAR_LOWER;
      }
      if (action === 'reset') {
        sysSessionStatusBar.zIndex = DefaultPanelZIndex.PANEL_STATUS_BAR;
      }
      log.showInfo(`setStatusBarZIndex success, zIndex: ${sysSessionStatusBar.zIndex}`);
    } catch (err) {
      log.showError(`setStatusBarZIndex failed, err: ${err}`);
    }
  }

  /**
   * 向状态栏发送智控键事件
   */
  public static postStatusBarFingerprintEvent(event: FingerprintEvent): void {
    sEventManager.publish(obtainLocalEvent(EventConstants.STATUS_BAR_DROPDOWN_FINGER_PRINT, event));
  }

  /**
   * 录屏进程异常被杀时,关闭触摸轨迹开关
   *
   * @param bundle 进程bundle
   * @param reason 进程取消通知原因
   */
  public static async appDeadNtfCancelHandle(bundle: string | undefined, reason: number | undefined): Promise<void> {
    try {
      if (bundle === SCREEN_RECORDE_BUNDLE_NAME && reason === ABNORMAL_REASON_CODE) {
        const result = await settings.setValue(GlobalContext.getContext(), 'settings.input.show_touch_hint', 'false');
        log.showInfo(`Set ShowTouch off ${result}`);
      }
    } catch (error) {
      log.showError(`Set Touch hint error:${error?.message}`);
    }
  }

  /**
   * 显示toast
   */
  @threadCall()
  public static showToast(message?: string, duration?: number, showMode?: number): void {
    try {
      ArkUIAdapter.uiContext?.getPromptAction().showToast({
        message: message,
        duration: duration,
        showMode: showMode,
      });
    } catch (error) {
      log.showError('showToast error by [%{public}d] [%{public}s]', error.code, error.message);
    }
  }

  /**
   * 判断是否为可扩展设备外屏支持的应用
   */
  @threadCall()
  public static isOuterBlockApp(bundleName: string, abilityName?: string): boolean | Promise<boolean> {
    // 组织查询参数
    let appArr: AppBundleInfo[] = [{
      bundleName: bundleName,
      abilityNames: abilityName ? [abilityName] : [],
    }];

    let isBlocked = true;
    // 查询是否为外屏支持应用
    const params = JSON.stringify(appArr);
    let retStr = OuterAppManager.getInstance().isBlockApps(params);
    log.showWarn(`isBlockApps params: ${params} result: ${retStr} `);
    let result: AppInfo[] = JSON.parse(retStr);
    if (result.length) {
      isBlocked = !result[0].appIsOuterSupport;
      // 若传入了abilityName, 还需判断对应的abilityName是否支持外屏
      if (abilityName && result[0].abilityInfos?.length) {
        isBlocked = !result[0].abilityInfos[0].appIsOuterSupport;
      }
      log.showInfo(`isOuterBlockApp bundleName: ${bundleName} abilityName: ${abilityName} isBlocked: ${isBlocked}`);
    }
    return isBlocked;
  }

  /**
   * 向状态栏发送隐藏事件
   */
  @threadCall()
  public static postStatusBarHideEvent(): void {
    sEventManager.publish(obtainLocalEvent(StatusBarEventType.STATUS_BAR_HIDE_IN_APP, true));
  }

  @threadCall()
  public static openAppNtfMgmt(bundleName: string, abilityName: string, appIndex: number) {
    log.showInfo(`handleAppNtfMgmtClick bundleName: ${bundleName}, appIndex: ${appIndex}`);
    try {
      GlobalContext.getContext().startAbility({
        bundleName: bundleName,
        abilityName: abilityName,
        parameters: {
          'linkFeature': NotificationConstants.APP_NTF_MGMT,
          'ohos.extra.param.key.appCloneIndex': appIndex
        }
      });
    } catch (e) {
      log.error(`open app notification management for ${bundleName} error:`, e);
    }
  }

  /**
   * 获取应用内通知管理abilityName
   * @param bundleName 包名
   * @returns
   */
  public static getAppNtfMgmtAbilityName(bundleName: string): string {
    if (!bundleName) {
      return '';
    }
    try {
      const abilityInfos =
        bundleManager.queryAbilityInfoSync({
          bundleName: bundleName,
          parameters: { linkFeature: NotificationConstants.APP_NTF_MGMT }
        }, bundleManager.AbilityFlag.GET_ABILITY_INFO_DEFAULT | bundleManager.AbilityFlag.GET_ABILITY_INFO_WITH_SKILL);
      for (const abilityInfo of abilityInfos) {
        if (abilityInfo?.skills?.flatMap(skill => skill?.uris)?.find(uri => uri?.linkFeature ===
        NotificationConstants.APP_NTF_MGMT)) {
          return abilityInfo.name;
        }
      }
    } catch (e) {
      // 17700001 - The specified bundleName is not found.
      // 17700003 - The specified ability is not found.
      if (e.code !== 17700003 && e.code !== 17700001) {
        log.error(`Get app notification management abilityName for ${bundleName} error: `, e);
      }
    }
    return '';
  }
}