import { useRef, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation } from 'react-query';

import i18next from 'i18next';
import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import Stack from '@material-hu/mui/Stack';

import { type AutocompleteOption } from '@material-hu/components/design-system/Inputs/Autocomplete/types';
import useSnackbar from '@material-hu/components/design-system/Snackbar';

import { type Language } from 'src/constants/languages';
import { useAuth } from 'src/contexts/JWTContext';
import useCommunityFeature from 'src/hooks/useCommunityFeature';
import useGeneralError from 'src/hooks/useGeneralError';
import useThemeMode from 'src/hooks/useThemeMode';
import { refetchAllTranslations } from 'src/pages/dashboard/feed/queries';
import { invalidateAllTranslations } from 'src/pages/dashboard/groups/queries';
import { changeLanguageUser, patchUserLanguage } from 'src/services/users';
import { CommunityFeature } from 'src/types/communityFeatures';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { setDocumentLanguage } from 'src/utils/languages';

import { useTranslation } from '../i18n';

import AppearanceSection from './components/AppearanceSection';
import PlatformLanguageSection from './components/PlatformLanguageSection';
import { SettingsChangeLanguageForm } from './SettingsChangeLanguageForm';

type SettingsFormValues = {
  postTranslationLanguage: AutocompleteOption | null;
};

const toLanguageOption = (
  code: string,
  translate: (key: string) => string,
): AutocompleteOption => ({
  value: code,
  label: translate(`language_${code.toLowerCase().replace('-', '_')}`),
});

export const useSettingsDrawer = () => {
  const {
    user,
    changePostTranslationLanguage,
    changeLanguage: changeUserLanguage,
  } = useAuth();
  const { t } = useTranslation();
  const { t: tSettings } = useLokaliseTranslation('settings');
  const { t: tDashboard } = useLokaliseTranslation('dashboard');
  const { enqueueSnackbar } = useSnackbar();
  const showGeneralError = useGeneralError();
  const canTranslate = useCommunityFeature(CommunityFeature.TRANSLATE_POSTS);
  const { commitThemeMode, resetThemeMode, selectedMode, themeMode } =
    useThemeMode();

  const { id: userId, postTranslationLanguage } = user!;

  // --- Platform language draft (applied only on "Guardar") ---
  const initialLanguageRef = useRef<Language>(user?.language as Language);
  const [draftLanguage, setDraftLanguage] = useState<Language>(
    user?.language as Language,
  );

  const { mutateAsync: commitPlatformLanguage } = useMutation({
    mutationFn: (language: Language) => changeLanguageUser(userId, language),
    onSuccess: (_, language) => {
      // Apply the language change only once the save succeeds.
      changeUserLanguage?.(language);
      setDocumentLanguage(language);
      i18next.changeLanguage(language);
      initialLanguageRef.current = language;
    },
    onError: err => {
      showGeneralError(err, t('CHANGE_LANGUAGE_ERROR'));
    },
  });

  // --- Colleague posts translation language ---
  const defaultOption = postTranslationLanguage
    ? toLanguageOption(postTranslationLanguage, tDashboard)
    : null;

  const form = useForm<SettingsFormValues>({
    defaultValues: { postTranslationLanguage: defaultOption },
  });

  const { mutateAsync: changeLanguageMutate } = useMutation({
    mutationFn: (language: string) => patchUserLanguage(language, userId),
    onSuccess: response => {
      invalidateAllTranslations();
      refetchAllTranslations();
      changePostTranslationLanguage?.(response.data);
    },
  });

  const handleSave = () => {
    const themeChanged = selectedMode !== themeMode;
    const platformLanguageChanged =
      draftLanguage !== initialLanguageRef.current;
    const newPostLanguage = form.getValues().postTranslationLanguage?.value;
    const postLanguageChanged =
      canTranslate &&
      (newPostLanguage ?? null) !== (postTranslationLanguage ?? null);

    // Theme: persist the previewed mode (synchronous, local).
    if (themeChanged) {
      commitThemeMode();
    }

    // Language changes hit the backend; gather them to confirm together.
    const tasks: Promise<unknown>[] = [];

    // Platform language: apply only on save, and only if it changed.
    if (platformLanguageChanged) {
      tasks.push(commitPlatformLanguage(draftLanguage));
    }

    // Colleague posts language: apply only if it changed.
    if (postLanguageChanged && newPostLanguage) {
      tasks.push(changeLanguageMutate(String(newPostLanguage)));
    }

    // A single confirmation once every changed preference is saved. Synchronous
    // theme-only changes resolve immediately (empty task list). Errors are
    // already surfaced by each mutation's onError.
    if (themeChanged || platformLanguageChanged || postLanguageChanged) {
      Promise.all(tasks)
        .then(() => {
          enqueueSnackbar({
            title: tSettings('preferences_updated'),
            variant: 'success',
          });
        })
        .catch(() => undefined);
    }

    closeDrawer();
  };

  const handleClose = () => {
    // Discard the unsaved theme preview and language draft.
    resetThemeMode();
    setDraftLanguage(initialLanguageRef.current);
    form.reset();
    closeDrawer();
  };

  const {
    drawer,
    showDrawer: openDrawer,
    closeDrawer,
  } = useDrawerV2(() => ({
    title: tSettings('preferences'),
    children: (
      <Stack gap={2}>
        <PlatformLanguageSection
          value={draftLanguage}
          onChange={setDraftLanguage}
        />
        {canTranslate && (
          <FormProvider {...form}>
            <SettingsChangeLanguageForm />
          </FormProvider>
        )}
        <AppearanceSection />
      </Stack>
    ),
    onClose: handleClose,
    primaryButtonProps: {
      children: tSettings('save'),
      fullWidth: true,
      onClick: handleSave,
    },
  }));

  const showDrawer = () => {
    // Snapshot the current language as the revert baseline for this session.
    initialLanguageRef.current = user?.language as Language;
    setDraftLanguage(user?.language as Language);
    openDrawer({});
  };

  return { drawer, showDrawer };
};
