export const scopeMessages = defineMessages({
  userReadEmailLabel: {
    id: "scopes.userReadEmail.label",
    defaultMessage: "Read user email",
  },
  userReadEmailDescription: {
    id: "scopes.userReadEmail.description",
    defaultMessage: "Read your email",
  },
  userReadLabel: {
    id: "scopes.userRead.label",
    defaultMessage: "Read user data",
  },
  userReadDescription: {
    id: "scopes.userRead.description",
    defaultMessage: "Access your public profile information",
  },
  userWriteLabel: {
    id: "scopes.userWrite.label",
    defaultMessage: "Write user data",
  },
  userWriteDescription: {
    id: "scopes.userWrite.description",
    defaultMessage: "Write to your profile",
  },
  userDeleteLabel: {
    id: "scopes.userDelete.label",
    defaultMessage: "Delete your account",
  },
  userDeleteDescription: {
    id: "scopes.userDelete.description",
    defaultMessage: "Delete your account",
  },
  userAuthWriteLabel: {
    id: "scopes.userAuthWrite.label",
    defaultMessage: "Write auth data",
  },
  userAuthWriteDescription: {
    id: "scopes.userAuthWrite.description",
    defaultMessage: "Modify your authentication data",
  },
  notificationReadLabel: {
    id: "scopes.notificationRead.label",
    defaultMessage: "Read notifications",
  },
  notificationReadDescription: {
    id: "scopes.notificationRead.description",
    defaultMessage: "Read your notifications",
  },
  notificationWriteLabel: {
    id: "scopes.notificationWrite.label",
    defaultMessage: "Write notifications",
  },
  notificationWriteDescription: {
    id: "scopes.notificationWrite.description",
    defaultMessage: "Delete/View your notifications",
  },
  payoutsReadLabel: {
    id: "scopes.payoutsRead.label",
    defaultMessage: "Read payouts",
  },
  payoutsReadDescription: {
    id: "scopes.payoutsRead.description",
    defaultMessage: "Read your payouts data",
  },
  payoutsWriteLabel: {
    id: "scopes.payoutsWrite.label",
    defaultMessage: "Write payouts",
  },
  payoutsWriteDescription: {
    id: "scopes.payoutsWrite.description",
    defaultMessage: "Withdraw money",
  },
  analyticsLabel: {
    id: "scopes.analytics.label",
    defaultMessage: "Read analytics",
  },
  analyticsDescription: {
    id: "scopes.analytics.description",
    defaultMessage: "Access your analytics data",
  },
  projectCreateLabel: {
    id: "scopes.projectCreate.label",
    defaultMessage: "Create projects",
  },
  projectCreateDescription: {
    id: "scopes.projectCreate.description",
    defaultMessage: "Create new projects",
  },
  projectReadLabel: {
    id: "scopes.projectRead.label",
    defaultMessage: "Read projects",
  },
  projectReadDescription: {
    id: "scopes.projectRead.description",
    defaultMessage: "Read all your projects",
  },
  projectWriteLabel: {
    id: "scopes.projectWrite.label",
    defaultMessage: "Write projects",
  },
  projectWriteDescription: {
    id: "scopes.projectWrite.description",
    defaultMessage: "Write to project data",
  },
  projectDeleteLabel: {
    id: "scopes.projectDelete.label",
    defaultMessage: "Delete projects",
  },
  projectDeleteDescription: {
    id: "scopes.projectDelete.description",
    defaultMessage: "Delete your projects",
  },
  versionCreateLabel: {
    id: "scopes.versionCreate.label",
    defaultMessage: "Create versions",
  },
  versionCreateDescription: {
    id: "scopes.versionCreate.description",
    defaultMessage: "Create new versions",
  },
  versionReadLabel: {
    id: "scopes.versionRead.label",
    defaultMessage: "Read versions",
  },
  versionReadDescription: {
    id: "scopes.versionRead.description",
    defaultMessage: "Read all versions",
  },
  versionWriteLabel: {
    id: "scopes.versionWrite.label",
    defaultMessage: "Write versions",
  },
  versionWriteDescription: {
    id: "scopes.versionWrite.description",
    defaultMessage: "Write to version data",
  },
  versionDeleteLabel: {
    id: "scopes.versionDelete.label",
    defaultMessage: "Delete versions",
  },
  versionDeleteDescription: {
    id: "scopes.versionDelete.description",
    defaultMessage: "Delete a version",
  },
  reportCreateLabel: {
    id: "scopes.reportCreate.label",
    defaultMessage: "Create reports",
  },
  reportCreateDescription: {
    id: "scopes.reportCreate.description",
    defaultMessage: "Create reports",
  },
  reportReadLabel: {
    id: "scopes.reportRead.label",
    defaultMessage: "Read reports",
  },
  reportReadDescription: {
    id: "scopes.reportRead.description",
    defaultMessage: "Read reports",
  },
  reportWriteLabel: {
    id: "scopes.reportWrite.label",
    defaultMessage: "Write reports",
  },
  reportWriteDescription: {
    id: "scopes.reportWrite.description",
    defaultMessage: "Edit reports",
  },
  reportDeleteLabel: {
    id: "scopes.reportDelete.label",
    defaultMessage: "Delete reports",
  },
  reportDeleteDescription: {
    id: "scopes.reportDelete.description",
    defaultMessage: "Delete reports",
  },
  threadReadLabel: {
    id: "scopes.threadRead.label",
    defaultMessage: "Read threads",
  },
  threadReadDescription: {
    id: "scopes.threadRead.description",
    defaultMessage: "Read threads",
  },
  threadWriteLabel: {
    id: "scopes.threadWrite.label",
    defaultMessage: "Write threads",
  },
  threadWriteDescription: {
    id: "scopes.threadWrite.description",
    defaultMessage: "Write to threads",
  },
  patCreateLabel: {
    id: "scopes.patCreate.label",
    defaultMessage: "Create PATs",
  },
  patCreateDescription: {
    id: "scopes.patCreate.description",
    defaultMessage: "Create personal API tokens",
  },
  patReadLabel: {
    id: "scopes.patRead.label",
    defaultMessage: "Read PATs",
  },
  patReadDescription: {
    id: "scopes.patRead.description",
    defaultMessage: "View created API tokens",
  },
  patWriteLabel: {
    id: "scopes.patWrite.label",
    defaultMessage: "Write PATs",
  },
  patWriteDescription: {
    id: "scopes.patWrite.description",
    defaultMessage: "Edit personal API tokens",
  },
  patDeleteLabel: {
    id: "scopes.patDelete.label",
    defaultMessage: "Delete PATs",
  },
  patDeleteDescription: {
    id: "scopes.patDelete.description",
    defaultMessage: "Delete your personal API tokens",
  },
  sessionReadLabel: {
    id: "scopes.sessionRead.label",
    defaultMessage: "Read sessions",
  },
  sessionReadDescription: {
    id: "scopes.sessionRead.description",
    defaultMessage: "Read active sessions",
  },
  sessionDeleteLabel: {
    id: "scopes.sessionDelete.label",
    defaultMessage: "Delete sessions",
  },
  sessionDeleteDescription: {
    id: "scopes.sessionDelete.description",
    defaultMessage: "Delete sessions",
  },
  performAnalyticsLabel: {
    id: "scopes.performAnalytics.label",
    defaultMessage: "Perform analytics",
  },
  performAnalyticsDescription: {
    id: "scopes.performAnalytics.description",
    defaultMessage: "Perform analytics actions",
  },
  collectionCreateLabel: {
    id: "scopes.collectionCreate.label",
    defaultMessage: "Create collections",
  },
  collectionCreateDescription: {
    id: "scopes.collectionCreate.description",
    defaultMessage: "Create collections",
  },
  collectionReadLabel: {
    id: "scopes.collectionRead.label",
    defaultMessage: "Read collections",
  },
  collectionReadDescription: {
    id: "scopes.collectionRead.description",
    defaultMessage: "Read collections",
  },
  collectionWriteLabel: {
    id: "scopes.collectionWrite.label",
    defaultMessage: "Write collections",
  },
  collectionWriteDescription: {
    id: "scopes.collectionWrite.description",
    defaultMessage: "Write to collections",
  },
  collectionDeleteLabel: {
    id: "scopes.collectionDelete.label",
    defaultMessage: "Delete collections",
  },
  collectionDeleteDescription: {
    id: "scopes.collectionDelete.description",
    defaultMessage: "Delete collections",
  },
  organizationCreateLabel: {
    id: "scopes.organizationCreate.label",
    defaultMessage: "Create organizations",
  },
  organizationCreateDescription: {
    id: "scopes.organizationCreate.description",
    defaultMessage: "Create organizations",
  },
  organizationReadLabel: {
    id: "scopes.organizationRead.label",
    defaultMessage: "Read organizations",
  },
  organizationReadDescription: {
    id: "scopes.organizationRead.description",
    defaultMessage: "Read organizations",
  },
  organizationWriteLabel: {
    id: "scopes.organizationWrite.label",
    defaultMessage: "Write organizations",
  },
  organizationWriteDescription: {
    id: "scopes.organizationWrite.description",
    defaultMessage: "Write to organizations",
  },
  organizationDeleteLabel: {
    id: "scopes.organizationDelete.label",
    defaultMessage: "Delete organizations",
  },
  organizationDeleteDescription: {
    id: "scopes.organizationDelete.description",
    defaultMessage: "Delete organizations",
  },
  sessionAccessLabel: {
    id: "scopes.sessionAccess.label",
    defaultMessage: "Access sessions",
  },
  sessionAccessDescription: {
    id: "scopes.sessionAccess.description",
    defaultMessage: "Access modrinth-issued sessions",
  },
});

const scopeDefinitions = [
  {
    id: "USER_READ_EMAIL",
    value: BigInt(1) << BigInt(0),
    label: scopeMessages.userReadEmailLabel,
    desc: scopeMessages.userReadEmailDescription,
  },
  {
    id: "USER_READ",
    value: BigInt(1) << BigInt(1),
    label: scopeMessages.userReadLabel,
    desc: scopeMessages.userReadDescription,
  },
  {
    id: "USER_WRITE",
    value: BigInt(1) << BigInt(2),
    label: scopeMessages.userWriteLabel,
    desc: scopeMessages.userWriteDescription,
  },
  {
    id: "USER_DELETE",
    value: BigInt(1) << BigInt(3),
    label: scopeMessages.userDeleteLabel,
    desc: scopeMessages.userDeleteDescription,
  },
  {
    id: "USER_AUTH_WRITE",
    value: BigInt(1) << BigInt(4),
    label: scopeMessages.userAuthWriteLabel,
    desc: scopeMessages.userAuthWriteDescription,
  },
  {
    id: "NOTIFICATION_READ",
    value: BigInt(1) << BigInt(5),
    label: scopeMessages.notificationReadLabel,
    desc: scopeMessages.notificationReadDescription,
  },
  {
    id: "NOTIFICATION_WRITE",
    value: BigInt(1) << BigInt(6),
    label: scopeMessages.notificationWriteLabel,
    desc: scopeMessages.notificationWriteDescription,
  },
  {
    id: "PAYOUTS_READ",
    value: BigInt(1) << BigInt(7),
    label: scopeMessages.payoutsReadLabel,
    desc: scopeMessages.payoutsReadDescription,
  },
  {
    id: "PAYOUTS_WRITE",
    value: BigInt(1) << BigInt(8),
    label: scopeMessages.payoutsWriteLabel,
    desc: scopeMessages.payoutsWriteDescription,
  },
  {
    id: "ANALYTICS",
    value: BigInt(1) << BigInt(9),
    label: scopeMessages.analyticsLabel,
    desc: scopeMessages.analyticsDescription,
  },
  {
    id: "PROJECT_CREATE",
    value: BigInt(1) << BigInt(10),
    label: scopeMessages.projectCreateLabel,
    desc: scopeMessages.projectCreateDescription,
  },
  {
    id: "PROJECT_READ",
    value: BigInt(1) << BigInt(11),
    label: scopeMessages.projectReadLabel,
    desc: scopeMessages.projectReadDescription,
  },
  {
    id: "PROJECT_WRITE",
    value: BigInt(1) << BigInt(12),
    label: scopeMessages.projectWriteLabel,
    desc: scopeMessages.projectWriteDescription,
  },
  {
    id: "PROJECT_DELETE",
    value: BigInt(1) << BigInt(13),
    label: scopeMessages.projectDeleteLabel,
    desc: scopeMessages.projectDeleteDescription,
  },
  {
    id: "VERSION_CREATE",
    value: BigInt(1) << BigInt(14),
    label: scopeMessages.versionCreateLabel,
    desc: scopeMessages.versionCreateDescription,
  },
  {
    id: "VERSION_READ",
    value: BigInt(1) << BigInt(15),
    label: scopeMessages.versionReadLabel,
    desc: scopeMessages.versionReadDescription,
  },
  {
    id: "VERSION_WRITE",
    value: BigInt(1) << BigInt(16),
    label: scopeMessages.versionWriteLabel,
    desc: scopeMessages.versionWriteDescription,
  },
  {
    id: "VERSION_DELETE",
    value: BigInt(1) << BigInt(17),
    label: scopeMessages.versionDeleteLabel,
    desc: scopeMessages.versionDeleteDescription,
  },
  {
    id: "REPORT_CREATE",
    value: BigInt(1) << BigInt(18),
    label: scopeMessages.reportCreateLabel,
    desc: scopeMessages.reportCreateDescription,
  },
  {
    id: "REPORT_READ",
    value: BigInt(1) << BigInt(19),
    label: scopeMessages.reportReadLabel,
    desc: scopeMessages.reportReadDescription,
  },
  {
    id: "REPORT_WRITE",
    value: BigInt(1) << BigInt(20),
    label: scopeMessages.reportWriteLabel,
    desc: scopeMessages.reportWriteDescription,
  },
  {
    id: "REPORT_DELETE",
    value: BigInt(1) << BigInt(21),
    label: scopeMessages.reportDeleteLabel,
    desc: scopeMessages.reportDeleteDescription,
  },
  {
    id: "THREAD_READ",
    value: BigInt(1) << BigInt(22),
    label: scopeMessages.threadReadLabel,
    desc: scopeMessages.threadReadDescription,
  },
  {
    id: "THREAD_WRITE",
    value: BigInt(1) << BigInt(23),
    label: scopeMessages.threadWriteLabel,
    desc: scopeMessages.threadWriteDescription,
  },
  {
    id: "PAT_CREATE",
    value: BigInt(1) << BigInt(24),
    label: scopeMessages.patCreateLabel,
    desc: scopeMessages.patCreateDescription,
  },
  {
    id: "PAT_READ",
    value: BigInt(1) << BigInt(25),
    label: scopeMessages.patReadLabel,
    desc: scopeMessages.patReadDescription,
  },
  {
    id: "PAT_WRITE",
    value: BigInt(1) << BigInt(26),
    label: scopeMessages.patWriteLabel,
    desc: scopeMessages.patWriteDescription,
  },
  {
    id: "PAT_DELETE",
    value: BigInt(1) << BigInt(27),
    label: scopeMessages.patDeleteLabel,
    desc: scopeMessages.patDeleteDescription,
  },
  {
    id: "SESSION_READ",
    value: BigInt(1) << BigInt(28),
    label: scopeMessages.sessionReadLabel,
    desc: scopeMessages.sessionReadDescription,
  },
  {
    id: "SESSION_DELETE",
    value: BigInt(1) << BigInt(29),
    label: scopeMessages.sessionDeleteLabel,
    desc: scopeMessages.sessionDeleteDescription,
  },
  {
    id: "PERFORM_ANALYTICS",
    value: BigInt(1) << BigInt(30),
    label: scopeMessages.performAnalyticsLabel,
    desc: scopeMessages.performAnalyticsDescription,
  },
  {
    id: "COLLECTION_CREATE",
    value: BigInt(1) << BigInt(31),
    label: scopeMessages.collectionCreateLabel,
    desc: scopeMessages.collectionCreateDescription,
  },
  {
    id: "COLLECTION_READ",
    value: BigInt(1) << BigInt(32),
    label: scopeMessages.collectionReadLabel,
    desc: scopeMessages.collectionReadDescription,
  },
  {
    id: "COLLECTION_WRITE",
    value: BigInt(1) << BigInt(33),
    label: scopeMessages.collectionWriteLabel,
    desc: scopeMessages.collectionWriteDescription,
  },
  {
    id: "COLLECTION_DELETE",
    value: BigInt(1) << BigInt(34),
    label: scopeMessages.collectionDeleteLabel,
    desc: scopeMessages.collectionDeleteDescription,
  },
  {
    id: "ORGANIZATION_CREATE",
    value: BigInt(1) << BigInt(35),
    label: scopeMessages.organizationCreateLabel,
    desc: scopeMessages.organizationCreateDescription,
  },
  {
    id: "ORGANIZATION_READ",
    value: BigInt(1) << BigInt(36),
    label: scopeMessages.organizationReadLabel,
    desc: scopeMessages.organizationReadDescription,
  },
  {
    id: "ORGANIZATION_WRITE",
    value: BigInt(1) << BigInt(37),
    label: scopeMessages.organizationWriteLabel,
    desc: scopeMessages.organizationWriteDescription,
  },
  {
    id: "ORGANIZATION_DELETE",
    value: BigInt(1) << BigInt(38),
    label: scopeMessages.organizationDeleteLabel,
    desc: scopeMessages.organizationDeleteDescription,
  },
  {
    id: "SESSION_ACCESS",
    value: BigInt(1) << BigInt(39),
    label: scopeMessages.sessionAccessLabel,
    desc: scopeMessages.sessionAccessDescription,
  },
];

const Scopes = scopeDefinitions.reduce(
  (acc, scope) => {
    acc[scope.id] = scope.value;
    return acc;
  },
  {} as Record<string, bigint>,
);

export const restrictedScopes = [
  Scopes.PAT_READ,
  Scopes.PAT_CREATE,
  Scopes.PAT_WRITE,
  Scopes.PAT_DELETE,
  Scopes.SESSION_READ,
  Scopes.SESSION_DELETE,
  Scopes.SESSION_ACCESS,
  Scopes.USER_AUTH_WRITE,
  Scopes.USER_DELETE,
  Scopes.PERFORM_ANALYTICS,
];

export const scopeList = Object.entries(Scopes)
  .filter(([_, value]) => !restrictedScopes.includes(value))
  .map(([key, _]) => key);

export const getScopeValue = (scope: string) => {
  return Scopes[scope];
};

export const encodeScopes = (scopes: string[]) => {
  let scopeFlag = BigInt(0);

  // We iterate over the provided scopes
  for (const scope of scopes) {
    // We iterate over the entries of the Scopes object
    for (const [scopeName, scopeFlagValue] of Object.entries(Scopes)) {
      // If the scope name is the same as the provided scope, add the scope flag to the scopeFlag variable
      if (scopeName === scope) {
        scopeFlag = scopeFlag | scopeFlagValue;
      }
    }
  }

  return scopeFlag;
};

export const decodeScopes = (scopes: bigint | number) => {
  if (typeof scopes === "number") {
    scopes = BigInt(scopes);
  }

  const authorizedScopes = [];

  // We iterate over the entries of the Scopes object
  for (const [scopeName, scopeFlag] of Object.entries(Scopes)) {
    // If the scope flag is present in the provided number, add the scope name to the list
    if ((scopes & scopeFlag) === scopeFlag) {
      authorizedScopes.push(scopeName);
    }
  }

  return authorizedScopes;
};

export const hasScope = (scopes: bigint, scope: string) => {
  const authorizedScopes = decodeScopes(scopes);
  return authorizedScopes.includes(scope);
};

export const toggleScope = (scopes: bigint, scope: string) => {
  const authorizedScopes = decodeScopes(scopes);
  if (authorizedScopes.includes(scope)) {
    return encodeScopes(authorizedScopes.filter((authorizedScope) => authorizedScope !== scope));
  } else {
    return encodeScopes([...authorizedScopes, scope]);
  }
};

export const useScopes = () => {
  const { formatMessage } = useVIntl();

  const scopesToDefinitions = (scopes: bigint) => {
    const authorizedScopes = decodeScopes(scopes);
    return authorizedScopes.map((scope) => {
      const scopeDefinition = scopeDefinitions.find(
        (scopeDefinition) => scopeDefinition.id === scope,
      );
      if (!scopeDefinition) {
        throw new Error(`Scope ${scope} not found`);
      }
      return formatMessage(scopeDefinition.desc);
    });
  };

  const scopesToLabels = (scopes: bigint) => {
    const authorizedScopes = decodeScopes(scopes);
    return authorizedScopes.map((scope) => {
      const scopeDefinition = scopeDefinitions.find(
        (scopeDefinition) => scopeDefinition.id === scope,
      );
      if (!scopeDefinition) {
        throw new Error(`Scope ${scope} not found`);
      }
      return formatMessage(scopeDefinition.label);
    });
  };

  return {
    scopesToDefinitions,
    scopesToLabels,
  };
};
