import { createContext, FC, useContext, useMemo, useState } from 'react'
import { useLayoutContext } from '@/shared/context/layout-context'
import AutoCloseBracketsSetting from '@/features/settings/components/editor-settings/auto-close-brackets-setting'
import AutoCompleteSetting from '@/features/settings/components/editor-settings/auto-complete-setting'
import CodeCheckSetting from '@/features/settings/components/editor-settings/code-check-setting'
import PreviewTabsSetting from '@/features/settings/components/editor-settings/preview-tabs-setting'
import KeybindingSetting from '@/features/settings/components/editor-settings/keybinding-setting'
import PDFViewerSetting from '@/features/settings/components/editor-settings/pdf-viewer-setting'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import SpellCheckSetting from '@/features/settings/components/editor-settings/spell-check-setting'
import DictionarySetting from '@/features/settings/components/editor-settings/dictionary-setting'
import { useTranslation } from 'react-i18next'
import BreadcrumbsSetting from '@/features/settings/components/editor-settings/breadcrumbs-setting'
import NonBlinkingCursorSetting from '@/features/settings/components/editor-settings/non-blinking-cursor-setting'
import MathPreviewSetting from '@/features/settings/components/editor-settings/math-preview-setting'
import RootDocumentSetting from '@/features/settings/components/compiler-settings/root-document-setting'
import CompilerSetting from '@/features/settings/components/compiler-settings/compiler-setting'
import ImageNameSetting from '@/features/settings/components/compiler-settings/image-name-setting'
import DraftSetting from '@/features/settings/components/compiler-settings/draft-setting'
import StopOnFirstErrorSetting from '@/features/settings/components/compiler-settings/stop-on-first-error-setting'
import AutoCompileSetting from '@/features/settings/components/compiler-settings/auto-compile-setting'
import OverallThemeSetting from '@/features/settings/components/appearance-settings/overall-theme-setting'
import EditorThemeSetting from '@/features/settings/components/appearance-settings/editor-theme-setting'
import FontSizeSetting from '@/features/settings/components/appearance-settings/font-size-setting'
import LineHeightSetting from '@/features/settings/components/appearance-settings/line-height-setting'
import FontFamilySetting from '@/features/settings/components/appearance-settings/font-family-setting'
import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
import DarkModePdfSetting from '@/features/settings/components/appearance-settings/dark-mode-pdf-setting'

import { useProjectSettingsContext } from '@/features/editor-left-menu/context/project-settings-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import ProjectNotificationsSetting from '@/features/settings/components/editor-settings/project-notifications-setting'
import getMeta from '@/utils/meta'
import type {
  SettingsEntry,
  SettingsSection,
  SettingsSectionHook,
} from '@/features/settings/context/types'
import EditorTabsSetting from '../components/editor-settings/editor-tabs-setting'

const [referenceSearchSettingModule] = importOverleafModules(
  'referenceSearchSetting'
)
const ReferenceSearchSetting = referenceSearchSettingModule?.import.default

const editorTabExtraSectionHooks: SettingsSectionHook[] = importOverleafModules(
  'settingsModalEditorTabSections'
)
  .map((m: any) => m?.import?.default)
  .filter((h: unknown): h is SettingsSectionHook => typeof h === 'function')

const spellcheckExtraSectionHooks: SettingsSectionHook[] =
  importOverleafModules('settingsModalSpellcheckSections')
    .map((m: any) => m?.import?.default)
    .filter((h: unknown): h is SettingsSectionHook => typeof h === 'function')

const useSlotSections = (hooks: SettingsSectionHook[]): SettingsSection[] =>
  hooks.map(hook => hook()).filter((s): s is SettingsSection => s != null)

type SettingsModalState = {
  show: boolean
  setShow: (shown: boolean) => void
  activeTab: string | null | undefined
  setActiveTab: (tab: string | null | undefined) => void
  settingsTabs: SettingsEntry[]
  settingToTabMap: Map<string, string>
}

export const SettingsModalContext = createContext<
  SettingsModalState | undefined
>(undefined)

export const SettingsModalProvider: FC<React.PropsWithChildren> = ({
  children,
}) => {
  const { t } = useTranslation()
  const { isOverleaf } = getMeta('ol-ExposedSettings')
  const { overallTheme } = useProjectSettingsContext()

  // TODO ide-redesign-cleanup: Rename this field and move it directly into this context
  const { leftMenuShown, setLeftMenuShown } = useLayoutContext()

  const hasEmailNotifications = useFeatureFlag('email-notifications')
  const hasEditorTabs = useFeatureFlag('editor-tabs')

  const editorTabExtraSections = useSlotSections(editorTabExtraSectionHooks)
  const spellcheckExtraSections = useSlotSections(spellcheckExtraSectionHooks)

  const allSettingsTabs: SettingsEntry[] = useMemo(
    () => [
      {
        key: 'editor',
        title: t('editor'),
        icon: 'code',
        sections: [
          {
            key: 'general',
            settings: [
              {
                key: 'autoComplete',
                component: <AutoCompleteSetting />,
              },
              {
                key: 'autoPairDelimiters',
                component: <AutoCloseBracketsSetting />,
              },
              {
                key: 'nonBlinkingCursor',
                component: <NonBlinkingCursorSetting />,
              },
              {
                key: 'syntaxValidation',
                component: <CodeCheckSetting />,
              },
              {
                key: 'editorTabs',
                component: <EditorTabsSetting />,
                hidden: !hasEditorTabs,
              },
              {
                key: 'previewTabs',
                component: <PreviewTabsSetting />,
                hidden: !hasEditorTabs,
              },
              {
                key: 'mode',
                component: <KeybindingSetting />,
              },
              {
                key: 'pdfViewer',
                component: <PDFViewerSetting />,
              },
              {
                key: 'write-and-cite-settings',
                component: <ReferenceSearchSetting />,
                hidden: !ReferenceSearchSetting,
              },
            ],
          },
          {
            key: 'tools',
            title: t('tools'),
            settings: [
              {
                key: 'breadcrumbs-setting',
                component: <BreadcrumbsSetting />,
              },
              {
                key: 'mathPreview',
                component: <MathPreviewSetting />,
              },
            ],
          },
          ...editorTabExtraSections,
        ],
      },
      {
        key: 'spelling_and_language',
        title: t('spelling_and_language'),
        icon: 'spellcheck',
        sections: [
          {
            key: 'spellcheck',
            title: t('spellcheck'),
            settings: [
              {
                key: 'spellCheckLanguage',
                component: <SpellCheckSetting />,
              },
              {
                key: 'dictionary-settings',
                component: <DictionarySetting />,
              },
            ],
          },
          ...spellcheckExtraSections,
        ],
      },
      {
        key: 'compiler',
        title: t('compiler'),
        icon: 'picture_as_pdf',
        sections: [
          {
            key: 'general',
            settings: [
              {
                key: 'rootDocId',
                component: <RootDocumentSetting />,
              },
              {
                key: 'compiler',
                component: <CompilerSetting />,
              },
              {
                key: 'imageName',
                component: <ImageNameSetting />,
              },
              {
                key: 'draft',
                component: <DraftSetting />,
              },
              {
                key: 'stopOnFirstError',
                component: <StopOnFirstErrorSetting />,
              },
              {
                key: 'autoCompile',
                component: <AutoCompileSetting />,
              },
            ],
          },
        ],
      },
      {
        key: 'appearance',
        title: t('appearance'),
        icon: 'brush',
        sections: [
          {
            key: 'general',
            settings: [
              {
                key: 'overallTheme',
                component: <OverallThemeSetting />,
              },
              {
                key: 'editorTheme',
                component: <EditorThemeSetting />,
              },
              {
                key: 'pdfDarkMode',
                component: <DarkModePdfSetting />,
                hidden: overallTheme === 'light-',
              },
              {
                key: 'fontSize',
                component: <FontSizeSetting />,
              },
              {
                key: 'fontFamily',
                component: <FontFamilySetting />,
              },
              {
                key: 'lineHeight',
                component: <LineHeightSetting />,
              },
            ],
          },
        ],
      },

      {
        key: 'project_notifications',
        title: t('project_notifications'),
        icon: 'notifications' as const,
        sections: [
          {
            key: 'general',
            settings: [
              {
                key: 'projectNotifications',
                component: <ProjectNotificationsSetting />,
              },
            ],
          },
        ],
        hidden: !hasEmailNotifications,
      },

      {
        key: 'account_settings',
        title: t('account_settings'),
        icon: 'settings',
        href: '/user/settings',
      },
      {
        key: 'subscription',
        title: t('subscription'),
        icon: 'account_balance',
        href: '/user/subscription',
        hidden: !isOverleaf,
      },
    ],
    [
      t,
      hasEditorTabs,
      overallTheme,
      hasEmailNotifications,
      isOverleaf,
      editorTabExtraSections,
      spellcheckExtraSections,
    ]
  )

  const settingsTabs = useMemo(
    () => allSettingsTabs.filter(tab => !tab.hidden),
    [allSettingsTabs]
  )

  const settingToTabMap = useMemo(() => {
    const map = new Map<string, string>()
    settingsTabs
      .filter(t => 'sections' in t)
      .forEach(tab => {
        tab.sections.forEach(section => {
          section.settings.forEach(setting => {
            map.set(setting.key, tab.key)
          })
        })
      })
    return map
  }, [settingsTabs])

  const [activeTab, setActiveTab] = useState<string | null | undefined>(
    settingsTabs[0]?.key
  )

  const value = useMemo(
    () => ({
      show: leftMenuShown,
      setShow: setLeftMenuShown,
      activeTab,
      setActiveTab,
      settingsTabs,
      settingToTabMap,
    }),
    [
      leftMenuShown,
      setLeftMenuShown,
      activeTab,
      setActiveTab,
      settingsTabs,
      settingToTabMap,
    ]
  )

  return (
    // TODO ide-redesign-cleanup: Merge <EditorLeftMenuProvider> into <SettingsModalProvider>
    <EditorLeftMenuProvider>
      <SettingsModalContext.Provider value={value}>
        {children}
      </SettingsModalContext.Provider>
    </EditorLeftMenuProvider>
  )
}

export const useSettingsModalContext = () => {
  const value = useContext(SettingsModalContext)

  if (!value) {
    throw new Error(
      `useSettingsModalContext is only available inside SettingsModalProvider`
    )
  }

  return value
}
