import { abilityAccessCtrl, PermissionRequestResult, Permissions, Want } from "@kit.AbilityKit";
import { bundleManager } from '@kit.AbilityKit';
import { Unknown } from "@core/common";
import { ContextUtil } from "../context/ContextUtil";
import common from "@ohos.app.ability.common";

/**
 * 权限工具类
 * 提供常用权限的快捷申请方法
 * 需要调用 ContextUtil.init() 之后初始化
 */
export class PermissionUtils {
  private atManager: abilityAccessCtrl.AtManager;
  private context: common.UIAbilityContext;

  constructor() {
    this.atManager = abilityAccessCtrl.createAtManager();
    this.context = ContextUtil.getUIAbilityCtx();
  }

  /**
   * 检查单个权限是否已授权
   * @param {Permissions} permission 目标权限
   * @returns {Promise<boolean>} 是否已授权
   */
  private async checkPermissionGrant(permission: Permissions): Promise<boolean> {
    try {
      const bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); // 获取包含应用信息的 BundleInfo,比如应用名称、应用包名、应用组件
      const appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;

      if (!appInfo.accessTokenId) {
        return false;
      }

      const grantStatus: abilityAccessCtrl.GrantStatus = await this.atManager.checkAccessToken(appInfo.accessTokenId, permission);
      return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
    } catch (error) {
      throw this.wrapError(error, "检查授权失败");
    }
  }

  /**
   * 申请权限,拒绝后并二次向用户申请授权
   * @param {Array<Permissions>} permissions 目标权限
   * @returns {Promise<boolean>} 是否已授权
   */
  private async requestPermissionsEasy(permissions: Array<Permissions>): Promise<boolean> {
    try {
      // 第一次请求权限
      let request: PermissionRequestResult = await this.atManager.requestPermissionsFromUser(this.context, permissions);
      let isGranted = request.authResults.every(status => status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED);
      if (isGranted) return true;

      // 二次请求权限
      for (const permission of permissions) {
        if (!(await this.checkPermissionGrant(permission))) {
          const result = await this.atManager.requestPermissionOnSetting(this.context, [permission]);
          if (!result.every(status => status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)) {
            return false;
          }
        }
      }
      return true;
    } catch (error) {
      throw this.wrapError(error, "申请权限失败");
    }
  }

  /**
   * 检查权限是否被永久拒绝
   * @param {Array<Permissions>} permissions 目标权限
   * @returns {Promise<boolean>} 是否已拒绝
   */
  private async checkPermissionPermanentlyDenied(permissions: Array<Permissions>): Promise<boolean> {
    // 通过检查是否可以再次请求权限来判断是否被永久拒绝
    try {
      for (const permission of permissions) {
        // 如果已经授权,跳过
        if (await this.checkPermissionGrant(permission)) {
          continue;
        }

        // 尝试请求权限,是否还能弹出授权窗口
        const result = await this.atManager.requestPermissionsFromUser(this.context, [permission]);
        const isGranted = result.authResults.every(status => status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED);

        if (!isGranted) {
          return true;
        }
      }
      return false;
    } catch (error) {
      throw this.wrapError(error, "检查权限是否被拒绝失败");
    }
  }

  /**
   * 跳转到应用权限设置页面
   * @returns {Promise<void>} void
   */
  private async openPermissionSettings(): Promise<void> {
    const want: Want = {
      bundleName: 'com.huawei.hmos.settings', // 设置应用的bundleName
      abilityName: 'com.huawei.hmos.settings.MainAbility', // 设置应用的abilityName
      uri: 'application_info_entry', // 目标页面地址
      parameters: { 'pushParams': ContextUtil.getUIAbilityCtx().abilityInfo.bundleName } // 当前应用的完整包名
    }
    return ContextUtil.getUIAbilityCtx().startAbility(want)
  }

  /**
   * 统一封装业务异常,附加上下文提示
   * @param {unknown} error 捕获的异常
   * @param {string} message 补充说明
   * @returns {Error} 包装后的异常
   */
  private wrapError(error: Unknown, message: string): Error {
    if (error instanceof Error) {
      error.message = `${message}:${error.message}`;
      return error;
    }
    return new Error(message);
  }

  /**
   * 处理权限申请结果的公共方法
   * 统一处理权限申请成功/失败的逻辑和用户提示
   *
   * @param {string} permissionName 权限名称(用于错误提示)
   * @param {(granted: boolean) => void} callback 权限申请结果回调
   * @param {Array<Permissions>} permissions 申请的权限
   */
  private async handlePermissionResult(permissionName: string, callback: (granted: boolean) => void, permissions: Array<Permissions>): Promise<void> {
    // 先检查是否已经获得所有权限
    let allGranted = true;
    for (const permission of permissions) {
      if (!(await this.checkPermissionGrant(permission))) {
        allGranted = false;
        break;
      }
    }

    if (allGranted) {
      callback(true);
      return;
    }

    // 申请权限
    const grantResult = await this.requestPermissionsEasy(permissions);

    if (grantResult) {
      callback(true);
    } else {
      // 检查是否被永久拒绝
      const isPermanentlyDenied = await this.checkPermissionPermanentlyDenied(permissions);
      if (isPermanentlyDenied) {
        //ToastUtil.showToast(`${permissionName}被永久拒绝,请手动授予`);
        // 跳转到权限设置页面
        this.openPermissionSettings();
      } else {
        //ToastUtil.showToast(`${permissionName}获取失败`);
      }
      callback(false);
    }
  }

  /**
   * 申请存储权限(读写用户存储)
   * 用法示例:PermissionUtils.requestStoragePermission() { granted => ... }
   * @param callback 权限申请结果回调
   */
  public async requestStoragePermission(callback: (granted: boolean) => void): Promise<void> {
    const permissions: Permissions[] = [
      "ohos.permission.READ_MEDIA",
      "ohos.permission.WRITE_MEDIA"
    ];
    await this.handlePermissionResult('存储权限', callback, permissions);
  }

  /**
   * 申请相机权限
   * 用法示例:PermissionUtils.requestCameraPermission() { granted => ... }
   * @param callback 权限申请结果回调
   */
  public async requestCameraPermission(callback: (granted: boolean) => void): Promise<void> {
    const permissions: Permissions[] = ["ohos.permission.CAMERA"];
    await this.handlePermissionResult('相机权限', callback, permissions);
  }

  /**
   * 申请录音权限
   * 用法示例:PermissionUtils.requestAudioPermission() { granted => ... }
   * @param callback 权限申请结果回调
   */
  public async requestAudioPermission(callback: (granted: boolean) => void): Promise<void> {
    const permissions: Permissions[] = ["ohos.permission.MICROPHONE"];
    await this.handlePermissionResult('录音权限', callback, permissions);
  }
}