import { Alert, Linking, NativeModules, PermissionsAndroid, Platform } from "react-native";
import { getCometChatTranslation } from "../resources/CometChatLocalizeNew/LocalizationManager";
const t = getCometChatTranslation();
const { FileManager } = NativeModules;

let instance: PermissionUtilIOS;
const permissionStatus = {
  "Not Determined": 0,
  Restricted: 1,
  Denied: 2,
  Authorized: 3,
  Unknown: -1,
} as const;

const permissionStatusAndroid = {
  granted: 3,
  denied: 2,
  never_ask_again: 2,
} as any;

const permissibleResources = ["camera", "mic"] as const;

const permissionMapAndroid: any = {
  camera: PermissionsAndroid.PERMISSIONS.CAMERA,
  mic: PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
};

type TPermissibleResources = (typeof permissibleResources)[number];

type ValueOf<T> = T[keyof T];
type TPermissionStatus = ValueOf<typeof permissionStatus>;

const permissionStore: any = {
  camera: permissionStatus.Unknown,
  mic: permissionStatus.Unknown,
};

class PermissionUtilIOS {
  status = permissionStatus;
  constructor() {
    if (instance) {
      throw new Error("New instance cannot be created!!");
    }
    instance = this;
  }

  async init() {
    try {
      if (Platform.OS === "ios") {
        const res: Record<TPermissibleResources, TPermissionStatus> =
          await FileManager.checkResourcesPermission(["mic", "camera"]);
        for (const resourceType in res) {
          permissionStore[resourceType as TPermissibleResources] =
            res[resourceType as TPermissibleResources];
        }
        permissionStore.camera = res.camera;
        permissionStore.mic = res.mic;
      } else if (Platform.OS === "android") {
        for (const resourceType of permissibleResources) {
          const isGranted = await PermissionsAndroid.check(permissionMapAndroid[resourceType]);
          permissionStore[resourceType] = isGranted
            ? permissionStatus.Authorized
            : permissionStatus["Not Determined"];
        }
      }
      return true;
    } catch (error: any) {
      return false;
    }
  }

  async get(resources: TPermissibleResources[]) {
    return resources.map((resource) => {
      if (!permissibleResources.includes(resource)) {
        throw new Error("Invalid resource type");
      }
      return permissionStore[resource];
    });
  }

  async request(resources: TPermissibleResources[]) {
    for (const resource of resources) {
      if (!permissibleResources.includes(resource)) {
        throw new Error("Invalid resource type");
      }
    }
    if (Platform.OS === "ios") {
      const res: Record<TPermissibleResources, TPermissionStatus> =
        await FileManager.requestResourcesPermission(resources);
      for (const resourceType in res) {
        permissionStore[resourceType as TPermissibleResources] =
          res[resourceType as TPermissibleResources];
      }
    } else if (Platform.OS === "android") {
      const res: any = await PermissionsAndroid.requestMultiple(
        resources.map((item) => permissionMapAndroid[item])
      );
      const permissionMapAndroidRevert: any = {};
      for (const resource in permissionMapAndroid) {
        permissionMapAndroidRevert[permissionMapAndroid[resource]] = resource;
      }
      for (const androidResource in res) {
        permissionStore[permissionMapAndroidRevert[androidResource]] =
          permissionStatusAndroid[res[androidResource]];
      }
    }
  }

  async startResourceBasedTask(resources: TPermissibleResources[]) {
    const resourcePermStatuses = await this.get(resources);
    let allResourcesAllowed = true;
    for (let i = 0; i < resourcePermStatuses.length; i++) {
      const resourcePermStatus = resourcePermStatuses[i];
      if (
        resourcePermStatus === this.status["Not Determined"] ||
        (Platform.OS === "android" && resourcePermStatuses[i] === this.status.Denied)
      ) {
        await this.request([resources[i]]);
        [resourcePermStatuses[i]] = await this.get([resources[i]]);
      }
      if (resourcePermStatuses[i] === this.status.Denied) {
        allResourcesAllowed = false;
      }
    }
    if (allResourcesAllowed === false) {
      Alert.alert("", t("CAMERA_PERMISSION"), [
        {
          style: "cancel",
          text: t("CANCEL"),
        },
        {
          style: "default",
          text: t("SETTINGS"),
          onPress: () => {
            Linking.openSettings();
          },
        },
      ]);
    }
    return allResourcesAllowed;
  }
}

export const permissionUtil = Object.freeze(new PermissionUtilIOS());
