/*
This file is part of the Notesnook project (https://notesnook.com/)

Copyright (C) 2023 Streetwriters (Private) Limited

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

import { formatBytes } from "@notesnook/common";
import {
  SubscriptionPlan,
  SubscriptionProvider,
  SubscriptionStatus,
  User
} from "@notesnook/core";
import { strings } from "@notesnook/intl";
import notifee from "@notifee/react-native";
import Clipboard from "@react-native-clipboard/clipboard";
import dayjs from "dayjs";
import React from "react";
import { Appearance, Linking, Platform } from "react-native";
import { getVersion } from "react-native-device-info";
import { TextInput } from "react-native-gesture-handler";
import * as RNIap from "react-native-iap";
import { DatabaseLogger, db } from "../../common/database";
import { MMKV } from "../../common/database/mmkv";
import filesystem from "../../common/filesystem";
import { presentDialog } from "../../components/dialog/functions";
import { AppLockPassword } from "../../components/dialogs/applock-password";
import { endProgress, startProgress } from "../../components/dialogs/progress";
import ExportNotesSheet from "../../components/sheets/export-notes";
import { Issue } from "../../components/sheets/github/issue";
import { Progress } from "../../components/sheets/progress";
import { Update } from "../../components/sheets/update";
import {
  createFormRef,
  validators
} from "../../components/ui/input/form-input";
import { VaultStatusType, useVaultStatus } from "../../hooks/use-vault-status";
import { BackgroundSync } from "../../services/background-sync";
import BackupService from "../../services/backup";
import BiometricService from "../../services/biometrics";
import {
  ToastManager,
  VaultRequestType,
  eSendEvent,
  eSubscribeEvent,
  openVault,
  presentSheet
} from "../../services/event-manager";
import Navigation from "../../services/navigation";
import Notifications from "../../services/notifications";
import PremiumService from "../../services/premium";
import SettingsService from "../../services/settings";
import Sync from "../../services/sync";
import { clearAllStores } from "../../stores";
import { refreshAllStores } from "../../stores/create-db-collection-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { useUserStore } from "../../stores/use-user-store";
import { EDITOR_LINE_HEIGHT } from "../../utils/constants";
import {
  eAfterSync,
  eCloseSheet,
  eOpenRecoveryKeyDialog
} from "../../utils/events";
import { sleep } from "../../utils/time";
import { resetTabStore } from "../editor/tiptap/use-tab-store";
import { MFARecoveryCodes, MFASheet } from "./2fa";
import { useDragState } from "./editor/state";
import { verifyUser, verifyUserWithApplock } from "./functions";
import { logoutUser } from "./logout";
import { SettingSection } from "./types";
import { getTimeLeft } from "./user-section";

export const settingsGroups: SettingSection[] = [
  {
    id: "account-local",
    name: strings.account(),
    useHook: () => useUserStore((state) => state.user),
    hidden: (current) => !!current,
    sections: [
      {
        id: "delete-data",
        name: strings.deleteData(),
        icon: "delete",
        description: strings.deleteAccountDesc(),
        modifer: () => {
          presentDialog({
            title: strings.deleteData(),
            paragraph: strings.irreverisibleAction(),
            positiveType: "errorShade",
            positiveText: "Delete data",
            positivePress: async () => {
              await PremiumService.setPremiumStatus();
              await BiometricService.resetCredentials();
              MMKV.clearStore();
              resetTabStore();
              clearAllStores();
              Navigation.queueRoutesForUpdate();
              SettingsService.resetSettings();
              db.reset();

              setImmediate(() => {
                refreshAllStores();
                eSendEvent(eAfterSync);
              });
              return true;
            }
          });
        }
      }
    ]
  },
  {
    id: "account",
    name: strings.account(),
    useHook: () => useUserStore((state) => state.user),
    hidden: (current) => !current,
    sections: [
      {
        id: "subscription-status",
        useHook: () => useUserStore((state) => state.user),
        hidden: (current) => {
          const user = current as User;
          return (
            !user ||
            !user.subscription ||
            user.subscription.provider === undefined ||
            !strings.subscriptionProviderInfo[user?.subscription?.provider] ||
            user.subscription?.plan === SubscriptionPlan.FREE
          );
        },
        name: (current) => {
          const user = (current as User) || useUserStore.getState().user;
          return (
            strings.subscriptionProviderInfo[
              user?.subscription?.provider
            ]?.title() || `Unknown provider id: ${user?.subscription?.provider}`
          );
        },
        icon: "credit-card",
        modifer: () => {
          const user = useUserStore.getState().user;
          if (!user) return;
          const subscriptionProviderInfo =
            strings.subscriptionProviderInfo[user?.subscription?.provider];

          if (!subscriptionProviderInfo) return;

          const isCurrentPlatform =
            (user.subscription?.provider === SubscriptionProvider.APPLE &&
              Platform.OS === "ios") ||
            (user.subscription?.provider === SubscriptionProvider.GOOGLE &&
              Platform.OS === "android");

          if (
            (user.subscription?.provider === SubscriptionProvider.GOOGLE ||
              user.subscription?.provider === SubscriptionProvider.APPLE) &&
            isCurrentPlatform &&
            user?.subscription?.productId
          ) {
            RNIap.deepLinkToSubscriptions({
              sku: user?.subscription.productId
            });
          } else {
            presentSheet({
              title: subscriptionProviderInfo.title(),
              paragraph: subscriptionProviderInfo.desc()
            });
          }
        },
        description: (current) => {
          const user = current as User;
          if (!user) return strings.neverHesitate();
          const subscriptionDaysLeft =
            user && getTimeLeft(user.subscription?.expiry);
          const expiryDate = dayjs(user?.subscription?.expiry).format(
            "dddd, MMMM D, YYYY h:mm A"
          );
          const startDate = dayjs(user?.subscription?.start).format(
            "dddd, MMMM D, YYYY h:mm A"
          );

          const trialEndDate = dayjs(user?.subscription?.start)
            .add(
              user?.subscription?.productId?.includes("monthly") ? 7 : 14,
              "day"
            )
            .format("dddd, MMMM D, YYYY h:mm A");

          if (
            user.subscription?.plan !== SubscriptionPlan.FREE &&
            user.subscription?.productId
          ) {
            const status = user.subscription?.status;
            return status === SubscriptionStatus.TRIAL
              ? strings.trialOnGoing(trialEndDate)
              : status === SubscriptionStatus.ACTIVE
                ? strings.subRenewOn(expiryDate)
                : status === SubscriptionStatus.CANCELED ||
                  status === SubscriptionStatus.PAUSED
                  ? strings.subEndsOn(expiryDate)
                  : status === SubscriptionStatus.EXPIRED
                    ? subscriptionDaysLeft.time < -3
                      ? strings.subEnded()
                      : strings.accountDowngradedIn(3)
                    : strings.neverHesitate();
          }

          return strings.neverHesitate();
        }
      },
      {
        id: "redeem-gift-code",
        name: strings.redeemGiftCode(),
        description: strings.redeemGiftCodeDesc(),
        hidden: (current) => {
          return !current as boolean;
        },
        useHook: () =>
          useUserStore(
            (state) => state.user?.subscription?.plan === SubscriptionPlan.FREE
          ),
        icon: "gift",
        modifer: () => {
          presentDialog({
            title: strings.redeemGiftCode(),
            paragraph: strings.redeemGiftCodeDesc(),
            form: {
              formRef: createFormRef({
                code: ""
              }),
              items: [
                {
                  name: "code",
                  placeholder: strings.code(),
                  ref: React.createRef<TextInput | null>(),
                  validators: [validators.required(strings.giftCodeRequired())]
                }
              ],
              onFormSubmit: async (form) => {
                try {
                  await db.subscriptions.redeemCode(form.getValue("code"));
                  return true;
                } catch (e) {
                  form.setError("code", (e as Error).message);
                  return false;
                }
              }
            },
            positiveText: strings.redeem()
          });
        }
      },
      {
        id: "account-settings",
        type: "screen",
        name: strings.manageAccount(),
        icon: "account-cog",
        description: strings.manageAccountDesc(),
        sections: [
          {
            id: "remove-profile-picture",
            name: strings.removeProfilePicture(),
            description: strings.removeProfilePictureDesc(),
            useHook: () =>
              useUserStore((state) => state.profile?.profilePicture),
            hidden: () => !useUserStore.getState().profile?.profilePicture,
            modifer: () => {
              presentDialog({
                title: strings.removeProfilePicture(),
                paragraph: strings.removeProfilePictureConfirmation(),
                positiveText: strings.remove(),
                positivePress: async () => {
                  db.settings
                    .setProfile({
                      profilePicture: undefined
                    })
                    .then(async () => {
                      useUserStore.setState({
                        profile: db.settings.getProfile()
                      });
                    });
                }
              });
            }
          },
          {
            id: "remove-name",
            name: strings.removeFullName(),
            description: strings.removeFullNameDesc(),
            useHook: () => useUserStore((state) => state.profile?.fullName),
            hidden: () => !useUserStore.getState().profile?.fullName,
            modifer: () => {
              presentDialog({
                title: strings.removeFullName(),
                paragraph: strings.removeFullNameConfirmation(),
                positiveText: strings.remove(),
                positivePress: async () => {
                  db.settings
                    .setProfile({
                      fullName: undefined
                    })
                    .then(async () => {
                      useUserStore.setState({
                        profile: db.settings.getProfile()
                      });
                    });
                }
              });
            }
          },
          {
            id: "recovery-key",
            name: strings.saveDataRecoveryKey(),
            modifer: async () => {
              verifyUser(null, async () => {
                await sleep(300);
                eSendEvent(eOpenRecoveryKeyDialog);
              });
            },
            description: strings.saveDataRecoveryKeyDesc(),
            icon: "key"
          },
          {
            id: "manage-attachments",
            name: strings.manageAttachments(),
            icon: "attachment",
            type: "screen",
            component: "attachments-manager",
            description: strings.manageAttachmentsDesc(),
            hideHeader: true
          },
          {
            id: "change-password",
            name: strings.changePassword(),
            type: "screen",
            description: strings.changePasswordDesc(),
            component: "change-password",
            icon: "form-textbox-password"
          },
          {
            id: "change-email",
            name: strings.changeEmail(),
            type: "screen",
            component: "change-email",
            description: strings.changeEmailDesc(),
            icon: "at"
          },
          {
            id: "2fa-settings",
            type: "screen",
            name: strings.twoFactorAuth(),
            description: strings.twoFactorAuthDesc(),
            icon: "two-factor-authentication",
            sections: [
              {
                id: "enable-2fa",
                name: strings.change2faMethod(),
                modifer: () => {
                  verifyUser("global", async () => {
                    MFASheet.present();
                  });
                },
                useHook: () => useUserStore((state) => state.user),
                description: strings.change2faMethodDesc()
              },
              {
                id: "2fa-fallback",
                name: strings.addFallback2faMethod(),
                useHook: () => useUserStore((state) => state.user),
                hidden: (user) => {
                  return (
                    !!(user as User)?.mfa?.secondaryMethod ||
                    !(user as User)?.mfa?.isEnabled
                  );
                },
                modifer: () => {
                  verifyUser("global", async () => {
                    MFASheet.present(true);
                  });
                },
                description: strings.addFallback2faMethodDesc()
              },
              {
                id: "change-2fa-method",
                name: strings.change2faFallbackMethod(),
                useHook: () => useUserStore((state) => state.user),
                hidden: (user) => {
                  return (
                    !(user as User)?.mfa?.secondaryMethod ||
                    !(user as User)?.mfa?.isEnabled
                  );
                },
                modifer: () => {
                  verifyUser("global", async () => {
                    MFASheet.present(true);
                  });
                },
                description: strings.change2faFallbackMethod()
              },
              {
                id: "view-2fa-codes",
                name: strings.viewRecoveryCodes(),
                modifer: () => {
                  verifyUser("global", async () => {
                    MFARecoveryCodes.present("sms");
                  });
                },
                useHook: () => useUserStore((state) => state.user),
                hidden: (user) => {
                  return !(user as User)?.mfa?.isEnabled;
                },
                description: strings.viewRecoveryCodesDesc()
              }
            ]
          },
          {
            id: "subscription-not-active",
            name: strings.subscriptionNotActivated(),
            useHook: () => useUserStore((state) => state.user),
            hidden: (user) =>
              Platform.OS !== "ios" ||
              (user as User)?.subscription?.plan !== SubscriptionPlan.FREE,
            modifer: async () => {
              if (Platform.OS === "android") return;
              try {
                presentSheet({
                  title: strings.loadingSubscription(),
                  paragraph: strings.loadingSubscriptionDesc(),
                  progress: true
                });
                const subscriptions = await RNIap.getPurchaseHistory();
                subscriptions.sort(
                  (a, b) => b.transactionDate - a.transactionDate
                );
                const currentSubscription = subscriptions[0];

                if (
                  !currentSubscription ||
                  dayjs(currentSubscription.transactionDate).isBefore(
                    dayjs().subtract(30, "day")
                  )
                ) {
                  ToastManager.show({
                    message: "No active subscription found",
                    type: "info"
                  });
                  eSendEvent(eCloseSheet);
                  return;
                }

                presentSheet({
                  title: strings.notesnookPro(),
                  paragraph: strings.subscribedOnVerify(
                    new Date(
                      currentSubscription.transactionDate
                    ).toLocaleString()
                  ),
                  action: async () => {
                    presentSheet({
                      title: strings.verifySubscription(),
                      paragraph: strings.subscriptionVerifyWait()
                    });
                    await PremiumService.subscriptions.verify(
                      currentSubscription
                    );
                    eSendEvent(eCloseSheet);
                  },
                  icon: "information-outline",
                  actionText: strings.verify()
                });
              } catch (e) {
                eSendEvent(eCloseSheet);
              }
            },
            description: strings.verifySubDesc()
          },
          {
            id: "clear-cache",
            name: strings.clearCache(),
            icon: "delete",
            modifer: async () => {
              presentDialog({
                title: strings.clearCacheConfirm(),
                paragraph: strings.clearCacheConfirmDesc(),
                positiveText: strings.clear(),
                positivePress: async () => {
                  filesystem.clearCache();
                  ToastManager.show({
                    heading: strings.cacheCleared(),
                    message: strings.cacheClearedDesc(),
                    type: "success"
                  });
                }
              });
            },
            description(current) {
              return strings.clearCacheDesc(current as number);
            },
            useHook: () => {
              const [cacheSize, setCacheSize] = React.useState(0);
              React.useEffect(() => {
                filesystem
                  .getCacheSize()
                  .then(setCacheSize)
                  .catch(() => {
                    /* empty */
                  });
                const sub = eSubscribeEvent("cache-cleared", () => {
                  setCacheSize(0);
                });
                return () => {
                  sub?.unsubscribe();
                };
              }, []);
              return formatBytes(cacheSize);
            }
          },

          {
            id: "logout",
            name: strings.logout(),
            description: strings.logoutWarnin(),
            icon: "logout",
            modifer: logoutUser
          },
          {
            id: "delete-account",
            type: "danger",
            name: strings.deleteAccount(),
            icon: "alert",
            description: strings.deleteAccountDesc(),
            modifer: () => {
              presentDialog({
                title: strings.deleteAccount(),
                paragraphColor: "red",
                paragraph: strings.deleteAccountDesc(),
                positiveType: "errorShade",
                input: true,
                secureTextEntry: true,
                inputPlaceholder: strings.enterAccountPassword(),
                positiveText: strings.delete(),
                positivePress: async (value) => {
                  try {
                    if (!value || !value.trim()) {
                      ToastManager.error(
                        new Error(strings.passwordNotEntered()),
                        undefined,
                        "local"
                      );
                      return;
                    }
                    const verified = await db.user?.verifyPassword(value);
                    if (verified) {
                      setTimeout(async () => {
                        try {
                          startProgress({
                            title: "Deleting account",
                            paragraph:
                              "Please wait while we delete your account"
                          });
                          await db.user?.deleteUser(value);
                          DatabaseLogger.info("User account deleted");
                          Navigation.navigate("Notes");
                          await BiometricService.resetCredentials();
                          SettingsService.set({
                            introCompleted: true
                          });
                        } catch (e) {
                          endProgress();
                          DatabaseLogger.error(e);
                          ToastManager.error(
                            e as Error,
                            strings.failedToDeleteAccount(),
                            "global"
                          );
                        }
                      }, 300);
                    } else {
                      ToastManager.show({
                        heading: strings.passwordIncorrect(),
                        type: "error",
                        context: "global"
                      });
                    }
                  } catch (e) {
                    ToastManager.error(
                      e as Error,
                      strings.failedToDeleteAccount(),
                      "global"
                    );
                  }
                }
              });
            }
          }
        ]
      },
      {
        id: "sync-settings",
        name: strings.syncSettings(),
        description: strings.syncSettingsDesc(),
        type: "screen",
        icon: "autorenew",
        component: "offline-mode-progress",
        sections: [
          {
            id: "offline-mode",
            icon: "download-multiple",
            name: strings.fullOfflineMode(),
            description: strings.fullOfflineModeDesc(),
            type: "switch",
            property: "offlineMode",
            featureId: "fullOfflineMode",
            modifer: () => {
              const current = SettingsService.get().offlineMode;
              if (current) {
                SettingsService.setProperty("offlineMode", false);
                db.fs().cancel("offline-mode");
                return;
              }
              SettingsService.setProperty("offlineMode", true);
              db.attachments.cacheAttachments().catch(() => {
                /* empty */
              });
            }
          },
          {
            id: "auto-sync",
            name: strings.disableAutoSync(),
            description: strings.disableAutoSyncDesc(),
            type: "switch",
            property: "disableAutoSync",
            featureId: "syncControls",
            icon: "sync-off"
          },
          {
            id: "disable-realtime-sync",
            name: strings.disableRealtimeSync(),
            description: strings.disableRealtimeSyncDesc(),
            type: "switch",
            property: "disableRealtimeSync",
            featureId: "syncControls"
          },
          {
            id: "disable-sync",
            name: strings.disableSync(),
            description: strings.disableSyncDesc(),
            type: "switch",
            property: "disableSync",
            featureId: "syncControls",
            icon: "cloud-off-outline"
          },
          {
            id: "background-sync",
            name: strings.backgroundSync(),
            description: strings.backgroundSyncDesc(),
            type: "switch",
            property: "backgroundSync",
            icon: "cloud-upload-outline",
            onChange: (value) => {
              if (value) {
                BackgroundSync.start();
              } else {
                BackgroundSync.stop();
              }
            }
          },
          {
            id: "pull-sync",
            name: strings.forcePullChanges(),
            description: strings.forcePullChangesDesc(),
            icon: "download",
            modifer: () => {
              presentDialog({
                title: strings.forcePullChanges(),
                paragraph: strings.forceSyncNotice(),
                negativeText: strings.cancel(),
                positiveText: strings.start(),
                positivePress: async () => {
                  eSendEvent(eCloseSheet);
                  await sleep(300);
                  Progress.present();
                  Sync.run("global", true, "fetch", () => {
                    eSendEvent(eCloseSheet);
                  });
                }
              });
            }
          },
          {
            id: "push-sync",
            name: strings.forcePushChanges(),
            description: strings.forcePushChangesDesc(),
            icon: "upload",
            modifer: () => {
              presentDialog({
                title: strings.forcePushChanges(),
                paragraph: strings.forceSyncNotice(),
                negativeText: strings.cancel(),
                positiveText: strings.start(),
                positivePress: async () => {
                  eSendEvent(eCloseSheet);
                  await sleep(300);
                  Progress.present();
                  Sync.run("global", true, "send", () => {
                    eSendEvent(eCloseSheet);
                  });
                }
              });
            }
          }
        ]
      },
      {
        id: "notesnook-circle",
        name: strings.notesnookCircle(),
        icon: "circle-outline",
        type: "screen",
        description: strings.notesnookCircleDesc(),
        component: "notesnook-circle"
      },
      {
        id: "inbox-api",
        name: strings.inboxAPI(),
        icon: "inbox",
        type: "screen",
        description: strings.inboxAPIDesc(),
        sections: [
          {
            id: "toggle-inbox-api",
            name: strings.enableInboxAPI(),
            description: strings.enableInboxAPIDesc(),
            type: "switch",
            useHook: () => {
              return useSettingStore((state) => state.inboxEnabled);
            },
            getter: (current) => current,
            modifer: async (current) => {
              if (current) {
                return new Promise((resolve) => {
                  presentDialog({
                    title: strings.disableInboxAPI(),
                    paragraph: strings.disableInboxAPIDesc(),
                    positiveText: strings.disable(),
                    onClose: () => {
                      resolve();
                    },
                    positivePress: async () => {
                      try {
                        await db.inboxItemsHistory.deleteFailed();
                        await db.user.discardInboxKeys();
                        useSettingStore.setState({
                          inboxEnabled: false
                        });
                        resolve();
                        return true;
                      } catch (e) {
                        ToastManager.show({
                          message: (e as Error).message,
                          context: "local"
                        });
                        DatabaseLogger.error(e);
                        return false;
                      }
                    }
                  });
                });
              }

              try {
                Navigation.push("SettingsGroup", {
                  id: "setup-inbox-keys",
                  name: strings.setupInboxKeys(),
                  type: "screen",
                  component: "setup-inbox-keys"
                } as any);
              } catch (e) {
                console.log(e);
              }
            }
          },
          {
            id: "manage-inbox-keys",
            name: strings.manageInboxKeys(),
            useHook: () => useSettingStore((state) => state.inboxEnabled),
            hidden: (current) => !current,
            description: strings.manageInboxKeysDesc(),
            onVerify: async () => {
              return new Promise((resolve) => {
                verifyUser(
                  "global",
                  () => {
                    resolve(true);
                  },
                  false,
                  () => resolve(false)
                );
              });
            },
            type: "screen",
            component: "manage-inbox-keys"
          },
          {
            id: "inbox-keys",
            name: strings.viewAPIKeys(),
            description: strings.viewAPIKeysDesc(),
            useHook: () => useSettingStore((state) => state.inboxEnabled),
            hidden: (current) => !current,
            type: "screen",
            component: "inbox-keys"
          },
          {
            id: "failed-inbox-items",
            name: strings.failedInboxItems(),
            description: strings.failedInboxItemsDesc(),
            useHook: () => useSettingStore((state) => state.inboxEnabled),
            hidden: (current) => !current,
            type: "screen",
            component: "failed-inbox-items",
            hideHeader: true
          }
        ]
      }
    ]
  },
  {
    id: "customize",
    name: strings.customization(),
    sections: [
      {
        id: "personalization",
        type: "screen",
        name: strings.appearance(),
        description: strings.appearanceDesc(),
        icon: "shape",
        sections: [
          {
            id: "theme-picker",
            type: "screen",
            name: strings.themes(),
            description: strings.themesDesc(),
            component: "theme-selector",
            icon: "shape"
          },
          {
            id: "use-system-theme",
            type: "switch",
            name: strings.useSystemTheme(),
            description: strings.useSystemThemeDesc(),
            property: "useSystemTheme",
            icon: "circle-half",
            modifer: () => {
              const current = SettingsService.get().useSystemTheme;
              SettingsService.set({
                useSystemTheme: !current
              });
              if (!current) {
                useThemeStore
                  .getState()
                  .setColorScheme(Appearance.getColorScheme() as any);
              }
            }
          },
          {
            id: "enable-dark-mode",
            type: "switch",
            name: strings.darkMode(),
            description: strings.darkModeDesc(),
            property: "colorScheme",
            icon: "brightness-6",
            modifer: () => {
              useThemeStore.getState().setColorScheme();
            },
            getter: () => useThemeStore.getState().colorScheme === "dark"
          }
        ]
      },
      {
        id: "behaviour",
        type: "screen",
        icon: "brain",
        name: strings.behavior(),
        description: strings.behaviorDesc(),
        sections: [
          {
            id: "default-sidebar-view",
            type: "component",
            name: strings.defaultSidebarTab(),
            description: strings.defaultSidebarTabDesc(),
            component: "sidebar-tab-selector"
          },
          {
            id: "date-format",
            name: strings.dateFormat(),
            description: strings.dateFormatDesc(),
            type: "component",
            component: "date-format-selector",
            icon: "calendar-blank"
          },
          {
            id: "day-format",
            name: strings.dayFormat(),
            description: strings.dayFormatDesc(),
            type: "component",
            component: "day-format-selector",
            icon: "calendar-today"
          },
          {
            id: "week-format",
            name: strings.weekFormat(),
            description: strings.weekFormatDesc(),
            type: "component",
            component: "week-format-selector",
            icon: "calendar"
          },
          {
            id: "time-format",
            name: strings.timeFormat(),
            description: strings.timeFormatDesc(),
            type: "component",
            component: "time-format-selector",
            icon: "clock-digital"
          },
          {
            id: "clear-trash-interval",
            type: "component",
            name: strings.clearTrashInterval(),
            description: strings.clearTrashIntervalDesc(),
            component: "trash-interval-selector",
            icon: "delete"
          },
          {
            id: "default-notebook",
            name: strings.clearDefaultNotebook(),
            description: strings.clearDefaultNotebookDesc(),
            modifer: () => {
              db.settings.setDefaultNotebook(undefined);
              ToastManager.show({
                heading: strings.defaultNotebookCleared(),
                type: "success"
              });
            },
            disabled: () => !db.settings.getDefaultNotebook(),
            icon: "notebook-minus"
          },
          {
            id: "disable-update-check",
            type: "switch",
            name: strings.autoUpdateCheck(),
            description: strings.autoUpdateCheckDesc(),
            property: "checkForUpdates",
            icon: "update"
          },
          {
            id: "keep-screen-on",
            type: "switch",
            name: strings.keepScreenOn(),
            description: strings.keepScreenOnDesc(),
            property: "keepScreenOn",
            icon: "cellphone-screenshot",
          },
          {
            id: "image-compression",
            type: "component",
            name: strings.imageCompression(),
            description: strings.imageCompressionDesc(),
            component: "image-compression-picker",
            icon: "image-area"
          }
        ]
      },
      {
        id: "editor",
        name: strings.editor(),
        type: "screen",
        icon: "note-edit-outline",
        description: strings.editorDesc(),
        sections: [
          {
            id: "configure-toolbar",
            type: "screen",
            name: strings.customizeToolbar(),
            description: strings.customizeToolbarDesc(),
            component: "configuretoolbar"
          },
          {
            id: "reset-toolbar",
            name: strings.resetToolbar(),
            description: strings.resetToolbarDesc(),
            modifer: () => {
              useDragState.getState().setPreset("default");
              ToastManager.show({
                heading: strings.toolbarReset(),
                type: "success"
              });
            }
          },
          {
            id: "double-spaced-lines",
            name: strings.doubleSpacedLines(),
            description: strings.doubleSpacedLinesDesc(),
            type: "switch",
            property: "doubleSpacedLines",
            icon: "format-line-spacing",
            onChange: () => {
              ToastManager.show({
                heading: strings.lineSpacingChanged(),
                type: "success"
              });
            }
          },
          {
            id: "default-font-size",
            name: strings.defaultFontSize(),
            description: strings.defaultFontSizeDesc(),
            type: "input-selector",
            minInputValue: 8,
            maxInputValue: 120,
            icon: "format-size",
            property: "defaultFontSize"
          },
          {
            id: "default-font-family",
            name: strings.defaultFontFamily(),
            description: strings.defaultFontFamilyDesc(),
            type: "component",
            icon: "format-font",
            property: "defaultFontFamily",
            component: "font-selector"
          },
          {
            id: "default-line-height",
            name: strings.lineHeight(),
            description: strings.lineHeightDesc(),
            type: "input-selector",
            property: "defaultLineHeight",
            icon: "format-line-spacing",
            minInputValue: EDITOR_LINE_HEIGHT.MIN,
            maxInputValue: EDITOR_LINE_HEIGHT.MAX
          },
          {
            id: "title-format",
            name: strings.titleFormat(),
            component: "title-format",
            description: strings.titleFormatDesc(),
            type: "component"
          },
          {
            id: "toggle-markdown",
            name: strings.mardownShortcuts(),
            property: "markdownShortcuts",
            description: strings.mardownShortcutsDesc(),
            type: "switch",
            featureId: "markdownShortcuts"
          }
        ]
      },
      {
        id: "servers",
        type: "screen",
        name: strings.servers(),
        description: strings.serversConfigurationDesc(),
        icon: "server",
        component: "server-config"
      }
    ]
  },
  {
    id: "privacy-security",
    name: strings.privacyAndSecurity(),
    sections: [
      {
        id: "marketing-emails",
        type: "switch",
        icon: "email-newsletter",
        name: strings.marketingEmails(),
        description: strings.marketingEmailsDesc(),
        modifer: async () => {
          try {
            await db.user?.changeMarketingConsent(
              !useUserStore.getState().user?.marketingConsent
            );
            useUserStore.getState().setUser(await db.user?.fetchUser());
          } catch (e) {
            ToastManager.error(e as Error);
          }
        },
        getter: (current: any) => current?.marketingConsent,
        useHook: () => useUserStore((state) => state.user),
        hidden: (current) => !current
      },
      {
        id: "cors-bypass",
        type: "input",
        name: strings.corsBypass(),
        description: strings.corsBypassDesc(),
        inputProperties: {
          defaultValue: "https://cors.notesnook.com",
          autoCorrect: false,
          keyboardType: "url"
        },
        property: "corsProxy",
        icon: "arrow-decision-outline"
      },

      {
        id: "vault",
        type: "screen",
        name: strings.vault(),
        description: strings.vaultDesc(),
        icon: "key",
        sections: [
          {
            id: "create-vault",
            name: strings.createVault(),
            description: strings.createVaultDesc(),
            icon: "key",
            useHook: useVaultStatus,
            hidden: (current) => (current as VaultStatusType)?.exists,
            modifer: () => {
              openVault({
                requestType: VaultRequestType.CreateVault,
                title: strings.createVault(),
                buttonTitle: strings.create()
              });
            }
          },
          {
            id: "lock-vault-after",
            type: "component",
            useHook: useVaultStatus,
            name: strings.lockVaultAfter(),
            description: strings.lockVaultAfterDesc(),
            hidden: (current) => !(current as VaultStatusType)?.exists,
            component: "vault-lock-timer",
            icon: "clock-outline"
          },
          {
            id: "change-vault-password",
            useHook: useVaultStatus,
            name: strings.changeVaultPassword(),
            description: strings.changeVaultPasswordDesc(),
            hidden: (current) => !(current as VaultStatusType)?.exists,
            modifer: () =>
              openVault({
                requestType: VaultRequestType.ChangePassword,
                title: strings.changeVaultPassword(),
                buttonTitle: strings.change()
              })
          },
          {
            id: "clear-vault",
            useHook: useVaultStatus,
            description: strings.clearVaultDesc(),
            name: strings.clearVault(),
            hidden: (current) => !(current as VaultStatusType)?.exists,
            modifer: () => {
              openVault({
                requestType: VaultRequestType.ClearVault,
                title: strings.clearVault() + "?",
                buttonTitle: strings.clear(),
                positiveButtonType: "errorShade"
              });
            }
          },
          {
            id: "delete-vault",
            name: strings.deleteVault(),
            description: strings.deleteVaultDesc(),
            useHook: useVaultStatus,
            hidden: (current) => !(current as VaultStatusType)?.exists,
            modifer: () => {
              openVault({
                requestType: VaultRequestType.DeleteVault,
                title: strings.deleteVault() + "?",
                buttonTitle: strings.delete(),
                positiveButtonType: "errorShade"
              });
            }
          },
          {
            id: "biometric-unlock",
            type: "switch",
            name: strings.biometricUnlock(),
            icon: "fingerprint",
            useHook: useVaultStatus,
            description: strings.biometricUnlockDesc(),
            hidden: (current) => {
              const _current = current as VaultStatusType;
              return !_current?.exists || !_current?.isBiometryAvailable;
            },
            getter: (current) => (current as VaultStatusType)?.biometryEnrolled,
            modifer: (current) => {
              const _current = current as VaultStatusType;
              const isRevoking = _current.biometryEnrolled;
              openVault({
                requestType: isRevoking
                  ? VaultRequestType.RevokeFingerprint
                  : VaultRequestType.EnableFingerprint,
                title: isRevoking
                  ? strings.revokeBiometricUnlock()
                  : strings.vaultEnableBiometrics(),
                buttonTitle: isRevoking ? strings.revoke() : strings.enable()
              });
            }
          }
        ]
      },
      {
        id: "privacy-mode",
        type: "switch",
        icon: "eye-off-outline",
        name: strings.privacyMode(),
        description: strings.privacyModeDesc(),
        modifer: () => {
          const settings = SettingsService.get();
          SettingsService.setPrivacyScreen(!settings.privacyScreen);
          SettingsService.set({ privacyScreen: !settings.privacyScreen });
        },
        property: "privacyScreen"
      },
      {
        id: "app-lock",
        name: strings.appLock(),
        type: "screen",
        description: strings.appLockDesc(),
        icon: "lock",
        featureId: "appLock",
        sections: [
          {
            id: "app-lock-mode",
            name: strings.enableAppLock(),
            description: strings.appLockDesc(),
            icon: "lock",
            type: "switch",
            property: "appLockEnabled",
            featureId: "appLock",
            onChange: (property) => {
              if (property) {
                SettingsService.set({
                  privacyScreen: true
                });
                SettingsService.setPrivacyScreen(true);
              }
            },
            onVerify: async () => {
              const verified = await verifyUserWithApplock();
              if (!verified) return false;

              if (!SettingsService.getProperty("appLockEnabled")) {
                if (
                  !SettingsService.getProperty("appLockHasPasswordSecurity") &&
                  (await BiometricService.isBiometryAvailable())
                ) {
                  SettingsService.setProperty("biometricsAuthEnabled", true);
                }

                if (
                  !(await BiometricService.isBiometryAvailable()) &&
                  !SettingsService.getProperty("appLockHasPasswordSecurity")
                ) {
                  ToastManager.show({
                    heading: strings.biometricsNotEnrolled(),
                    type: "error",
                    message: strings.biometricsNotEnrolledDesc()
                  });
                  return false;
                }
              }

              return verified;
            }
          },
          {
            id: "app-lock-timer",
            name: strings.appLockTimeout(),
            description: strings.appLockTimeoutDesc(),
            type: "component",
            component: "applock-timer"
          },
          {
            id: "app-lock-pin",
            name: () =>
              SettingsService.getProperty("applockKeyboardType") === "numeric"
                ? strings.setupAppLockPin()
                : strings.setupAppLockPassword(),

            description: () =>
              SettingsService.getProperty("applockKeyboardType") === "numeric"
                ? strings.setupAppLockPinDesc()
                : strings.setupAppLockPasswordDesc(),
            hidden: () => {
              return !!SettingsService.getProperty(
                "appLockHasPasswordSecurity"
              );
            },
            onVerify: () => {
              return verifyUserWithApplock();
            },
            property: "appLockHasPasswordSecurity",
            modifer: () => {
              AppLockPassword.present("create");
            }
          },
          {
            id: "app-lock-pin-change",
            name: () =>
              SettingsService.getProperty("applockKeyboardType") === "numeric"
                ? strings.changeAppLockPin()
                : strings.changeAppLockPassword(),
            description: () =>
              SettingsService.getProperty("applockKeyboardType") === "numeric"
                ? strings.changeAppLockPinDesc()
                : strings.changeAppLockPasswordDesc(),
            hidden: () => {
              return !SettingsService.getProperty("appLockHasPasswordSecurity");
            },
            property: "appLockHasPasswordSecurity",
            modifer: () => {
              AppLockPassword.present("change");
            }
          },
          {
            id: "app-lock-pin-remove",
            name: () =>
              SettingsService.getProperty("applockKeyboardType") === "numeric"
                ? strings.removeAppLockPin()
                : strings.removeAppLockPassword(),
            description: () =>
              SettingsService.getProperty("applockKeyboardType") === "numeric"
                ? strings.removeAppLockPinDesc()
                : strings.removeAppLockPasswordDesc(),
            hidden: () => {
              return !SettingsService.getProperty("appLockHasPasswordSecurity");
            },
            property: "appLockHasPasswordSecurity",
            modifer: () => {
              AppLockPassword.present("remove");
            }
          },
          {
            id: "app-lock-fingerprint",
            name: strings.unlockWithBiometrics(),
            description: strings.unlockWithBiometricsDesc(),
            type: "switch",
            property: "biometricsAuthEnabled",
            onVerify: async () => {
              const verified = await verifyUserWithApplock();
              if (!verified) return false;

              if (SettingsService.getProperty("biometricsAuthEnabled")) {
                if (
                  !SettingsService.getProperty("appLockHasPasswordSecurity")
                ) {
                  SettingsService.setProperty("appLockEnabled", false);
                  ToastManager.show({
                    heading: strings.appLockDisabled(),
                    type: "success"
                  });
                }
              }

              return verified;
            },
            icon: "fingerprint"
          }
        ]
      }
    ]
  },
  {
    id: "back-restore",
    name: strings.backupRestore(),
    sections: [
      {
        id: "backups",
        type: "screen",
        name: strings.backups(),
        icon: "backup-restore",
        description: strings.backupsDesc(),
        sections: [
          {
            id: "backup-now",
            name: strings.backupNow(),
            description: strings.backupNowDesc(),
            modifer: async () => {
              const user = useUserStore.getState().user;
              if (!user || SettingsService.getProperty("encryptedBackup")) {
                await BackupService.run(true);
                return;
              }

              verifyUser(null, () => BackupService.run(true));
            }
          },
          {
            id: "backup-now-with-attachments",
            name: strings.backupNowWithAttachments(),
            description: strings.backupNowWithAttachmentsDesc(),
            hidden: () => !useUserStore.getState().user,
            modifer: async () => {
              const user = useUserStore.getState().user;
              if (!user || SettingsService.getProperty("encryptedBackup")) {
                await BackupService.run(true, undefined, "full");
                return;
              }

              verifyUser(null, () =>
                BackupService.run(true, undefined, "full")
              );
            }
          },
          {
            id: "auto-backups",
            type: "component",
            name: strings.automaticBackups(),
            description: strings.automaticBackupsDesc(),
            component: "autobackups"
          },
          {
            id: "auto-backups-with-attachments",
            type: "component",
            hidden: () => !useUserStore.getState().user,
            name: strings.automaticBackupsWithAttachments(),
            description: [
              ...strings.automaticBackupsWithAttachmentsDesc()
            ].join("\n"),
            component: "autobackupsattachments"
          },
          {
            id: "select-backup-dir",
            name: strings.selectBackupDir(),
            description: () => {
              const desc = strings.selectBackupDirDesc(
                SettingsService.get().backupDirectoryAndroid?.path || ""
              );
              return desc[0] + " " + desc[1];
            },
            icon: "folder",
            hidden: () =>
              !!SettingsService.get().backupDirectoryAndroid ||
              Platform.OS !== "android",
            property: "backupDirectoryAndroid",
            modifer: async () => {
              let dir;
              try {
                dir = await BackupService.checkBackupDirExists(true);
              } catch (e) {
                console.error(e);
              } finally {
                if (!dir) {
                  ToastManager.show({
                    heading: strings.noDirectorySelected(),
                    type: "error"
                  });
                }
              }
            }
          },
          {
            id: "change-backup-dir",
            name: strings.changeBackupDir(),
            description: () =>
              SettingsService.get().backupDirectoryAndroid?.name || "",
            icon: "folder",
            hidden: () =>
              !SettingsService.get().backupDirectoryAndroid ||
              Platform.OS !== "android",
            property: "backupDirectoryAndroid",
            modifer: async () => {
              let dir;
              try {
                dir = await BackupService.checkBackupDirExists(true);
              } catch (e) {
                console.error(e);
              } finally {
                if (!dir) {
                  ToastManager.show({
                    heading: strings.noDirectorySelected(),
                    type: "error"
                  });
                }
              }
            }
          },
          {
            id: "enable-backup-encryption",
            type: "switch",
            name: strings.backupEncryption(),
            description: strings.backupEncryptionDesc(),
            icon: "lock",
            property: "encryptedBackup",
            modifer: async () => {
              const user = useUserStore.getState().user;
              const settings = SettingsService.get();
              if (!user) {
                ToastManager.show({
                  heading: strings.loginRequired(),
                  type: "error"
                });
                return;
              }
              if (settings.encryptedBackup) {
                await verifyUser(null, () => {
                  SettingsService.set({
                    encryptedBackup: false
                  });
                });
              } else {
                SettingsService.set({
                  encryptedBackup: true
                });
              }
            }
          }
        ]
      },
      {
        id: "restore-backup",
        name: strings.restoreBackup(),
        description: strings.restoreBackupDesc(),
        icon: "restore",
        type: "screen",
        component: "backuprestore"
      },
      {
        id: "export-notes",
        name: strings.exportAllNotes(),
        icon: "export",
        description: strings.exportAllNotesDesc(),
        modifer: () => {
          verifyUser(null, () => {
            ExportNotesSheet.present(undefined, true);
          });
        }
      }
    ]
  },
  {
    id: "productivity",
    name: strings.productivity(),
    sections: [
      {
        id: "notification-notes",
        type: "switch",
        name: strings.quickNoteNotification(),
        description: strings.quickNoteNotificationDesc(),
        property: "notifNotes",
        icon: "form-textbox",
        modifer: async () => {
          const settings = SettingsService.get();
          if (settings.notifNotes) {
            Notifications.unpinQuickNote();
          } else {
            Notifications.pinQuickNote();
          }
          SettingsService.set({
            notifNotes: !settings.notifNotes
          });
        },
        hidden: () => Platform.OS !== "android",
        featureId: "createNoteFromNotificationDrawer"
      },
      {
        id: "reminders",
        type: "screen",
        name: strings.reminders(),
        icon: "bell",
        description: strings.remindersDesc(),
        sections: [
          {
            id: "enable-reminders",
            property: "reminderNotifications",
            type: "switch",
            name: strings.reminderNotification(),
            icon: "bell-outline",
            onChange: (property) => {
              if (property) {
                Notifications.setupReminders();
              } else {
                Notifications.clearAllTriggers();
              }
            },
            description: strings.reminderNotificationDesc()
          },
          {
            id: "snooze-time",
            property: "defaultSnoozeTime",
            type: "input",
            name: strings.defaultSnoozeTime(),
            description: strings.defaultSnoozeTimeDesc(),
            inputProperties: {
              keyboardType: "decimal-pad",
              defaultValue: 5 + "",
              placeholder: strings.setSnoozeTimePlaceholder(),
              onSubmitEditing: () => {
                Notifications.setupReminders();
              }
            }
          },
          {
            id: "reminder-sound-ios",
            type: "screen",
            name: strings.changeNotificationSound(),
            description: strings.changeNotificationSoundDesc(),
            component: "sound-picker",
            icon: "bell-ring",
            hidden: () =>
              Platform.OS === "ios" ||
              (Platform.OS === "android" && Platform.Version > 25)
          },
          {
            id: "reminder-sound-android",
            name: strings.changeNotificationSound(),
            description: strings.changeNotificationSoundDesc(),
            icon: "bell-ring",
            hidden: () =>
              Platform.OS === "ios" ||
              (Platform.OS === "android" && Platform.Version < 26),
            modifer: async () => {
              const id = await Notifications.getChannelId("urgent");
              if (id) {
                await notifee.openNotificationSettings(id);
              }
            }
          }
        ]
      }
    ]
  },
  {
    id: "help-support",
    name: strings.helpAndSupport(),
    sections: [
      {
        id: "report-issue",
        name: strings.reportAnIssue(),
        icon: "bug",
        modifer: () => {
          presentSheet({
            //@ts-ignore Migrate to TS
            component: <Issue />
          });
        },
        description: strings.reportAnIssueDesc()
      },
      {
        id: "email-support",
        name: strings.emailSupport(),
        icon: "email",
        modifer: () => {
          Clipboard.setString("support@streetwriters.co");
          ToastManager.show({
            heading: strings.emailCopied(),
            type: "success",
            icon: "content-copy"
          });
          setTimeout(() => {
            Linking.openURL("mailto:support@streetwriters.co");
          }, 1000);
        },
        description: strings.emailSupportDesc()
      },
      {
        id: "docs-link",
        name: strings.documentation(),
        modifer: async () => {
          Linking.openURL("https://help.notesnook.com/");
        },
        description: strings.documentationDesc(),
        icon: "file-document"
      },
      {
        id: "debugging",
        name: strings.debugging(),
        description: strings.debuggingDesc(),
        type: "screen",
        icon: "bug",
        sections: [
          {
            id: "debug-logs",
            type: "screen",
            name: strings.debugLogs(),
            description: strings.debugLogsDesc(),
            component: "debug-logs"
          }
        ]
      }
    ]
  },
  {
    id: "community",
    name: strings.community(),
    sections: [
      {
        id: "join-telegram",
        name: strings.joinTelegram(),
        description: strings.joinTelegramDesc(),
        icon: "sc-telegram",
        iconFamily: "evilicons",
        iconSize: 35,
        modifer: () => {
          Linking.openURL("https://t.me/notesnook").catch(() => {
            /* empty */
          });
        }
      },
      {
        id: "join-mastodon",
        name: strings.joinMastodon(),
        description: strings.joinMastodonDesc(),
        icon: "mastodon",
        modifer: () => {
          Linking.openURL("https://fosstodon.org/@notesnook").catch(
            console.log
          );
        }
      },
      {
        id: "join-twitter",
        name: strings.followOnX(),
        description: strings.followOnXDesc(),
        icon: "twitter",
        modifer: () => {
          Linking.openURL("https://twitter.com/notesnook").catch(() => {
            /* empty */
          });
        }
      },
      {
        id: "join-discord",
        name: strings.joinDiscord(),
        icon: "discord",
        modifer: async () => {
          Linking.openURL("https://discord.gg/zQBK97EE22").catch(() => {
            /* empty */
          });
        },
        description: strings.joinDiscordDesc()
      }
    ]
  },
  {
    id: "legal",
    name: strings.legal(),
    sections: [
      {
        id: "tos",
        name: strings.tos(),
        icon: "briefcase-outline",
        modifer: async () => {
          try {
            await Linking.openURL("https://notesnook.com/tos");
          } catch (e) {
            console.error(e);
          }
        },
        description: strings.tosDesc()
      },
      {
        id: "privacy-policy",
        name: strings.privacyPolicy(),
        icon: "shield-outline",
        modifer: async () => {
          try {
            await Linking.openURL("https://notesnook.com/privacy");
          } catch (e) {
            console.error(e);
          }
        },
        description: strings.privacyPolicyDesc()
      },
      {
        id: "licenses",
        name: strings.licenses(),
        type: "screen",
        component: "licenses",
        description: strings.ossLibs(),
        icon: "open-source-initiative"
      }
    ]
  },
  {
    id: "about",
    name: strings.about(),
    sections: [
      {
        id: "download",
        name: strings.downloadOnDesktop(),
        icon: "monitor",
        modifer: async () => {
          try {
            await Linking.openURL("https://notesnook.com/downloads");
          } catch (e) {
            console.error(e);
          }
        },
        description: strings.downloadOnDesktopDesc()
      },
      {
        id: "roadmap",
        name: strings.roadmap(),
        icon: "chart-timeline",
        modifer: async () => {
          try {
            await Linking.openURL("https://notesnook.com/roadmap/");
          } catch (e) {
            console.error(e);
          }
        },
        description: strings.roadmapDesc()
      },
      {
        id: "check-for-updates",
        name: strings.checkForUpdates(),
        icon: "cellphone-arrow-down",
        description: strings.checkForUpdatesDesc(),
        modifer: async () => {
          presentSheet({
            //@ts-ignore // Migrate to ts
            component: (ref) => <Update fwdRef={ref} />
          });
        }
      },
      {
        id: "app-version",
        name: strings.appVersion(),
        icon: "alpha-v",
        modifer: async () => {
          try {
            await Linking.openURL("https://notesnook.com");
          } catch (e) {
            console.error(e);
          }
        },
        description: getVersion()
      }
    ]
  }
];
