import {
  type ChangeEvent,
  lazy,
  type ReactNode,
  useMemo,
  useState,
} from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation, useQuery } from 'react-query';

import { intersection } from 'lodash-es';
import { useModal } from '@material-hu/hooks/useModal';
import { IconProgressCheck, IconSettings } from '@material-hu/icons/tabler';
import { type IconButtonProps } from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import { appearFromBottom } from '@material-hu/utils/animations';

import AvatarSwitcherCard from '@material-hu/components/composed-components/AvatarSwitcherCard';
import Button from '@material-hu/components/design-system/Buttons/Button';
import Skeleton from '@material-hu/components/design-system/Skeleton';
import useSnackbar from '@material-hu/components/design-system/Snackbar';
import Title from '@material-hu/components/design-system/Title';

import useAuth from 'src/contexts/JWTContext';
import useCommunityFeature from 'src/hooks/useCommunityFeature';
import {
  capabilityToi18nKey,
  useCustomServerTranslation,
} from 'src/hooks/useCustomServerTranslation';
import useFeatureFlag from 'src/hooks/useFeatureFlag';
import {
  getAvailableCapabilities,
  updateInstance,
} from 'src/services/instancesService';
import { CommunityFeature } from 'src/types/communityFeatures';
import { FeatureFlags } from 'src/types/featureFlags';
import { type Instance } from 'src/types/instance';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { formatInstancePermissions } from 'src/utils/instanceUtils';
import { getModulesPermissions, UserPermissions } from 'src/utils/permissions';

import AcknowledgementsConfiguration from './AcknowledgementsConfiguration';
import ChatsConfiguration from './ChatsConfiguration';
import DocumentsOrder from './DocumentsOrder';
import FilesConfiguration from './FilesConfiguration';
import LearningConfiguration from './LearningConfiguration';
import { appsKeys } from './queries';
import {
  formatCapabilitiesChange,
  formatCapabilitiesData,
  formatCapabilitiesQuery,
  getCapabilityIcon,
  getCapabilityPills,
  HARDCODED_CAPABILITY_DESCRIPTIONS,
  HARDCODED_CAPABILITY_TITLES,
  setLogEventApps,
} from './utils';
import VacationsConfiguration from './VacationsConfiguration';
import ValidateOrgModal from './ValidateOrgModal';

const KnowledgeLibrariesSettingsDrawer = lazy(
  () => import('./KnowledgeLibrariesDrawer'),
);
const BirthdaySettingsDrawer = lazy(() => import('./BirthdaySettingsDrawer'));
const FeedSettingsDrawer = lazy(() => import('./FeedSettingsDrawer'));
const GroupsSettingsDrawer = lazy(() => import('./GroupsSettingsDrawer'));

// Filter deleted capabilities in frontend since backend still returns them.
// Removing them from backend would require extensive codebase changes.
const DELETED_CAPABILITIES = ['VIEW_TICKETS'];

enum OpenSettings {
  NONE = 'NONE',
  BIRTHDAY = 'BIRTHDAY',
  FEED = 'FEED',
  KNOWLEDGE_LIBRARIES = 'KNOWLEDGE_LIBRARIES',
  GROUPS = 'GROUPS',
}

const CapabilitiesList = () => {
  const theme = useTheme();
  const { t } = useLokaliseTranslation('apps');
  const { instance, user: loggedUser } = useAuth();
  const { enqueueSnackbar } = useSnackbar();
  const canLiveStreaming = useCommunityFeature(
    CommunityFeature.VIEW_LIVESTREAM,
  );
  const canPayrollMobilityAdo = useCommunityFeature(
    CommunityFeature.PAYROLL_MOBILITY_ADO,
  );
  const employeeLifecycleEnabled = useFeatureFlag(
    FeatureFlags.VIEW_EMPLOYEE_LIFECYCLE,
  );
  const chatV1Enabled = useFeatureFlag(FeatureFlags.CHATS_V1_AVAILABLE);

  const [openSettings, setOpenSettings] = useState(OpenSettings.NONE);

  const form = useForm({
    defaultValues: formatInstancePermissions(instance as Instance),
  });

  const {
    formState: { isSubmitting, isDirty },
    reset,
    handleSubmit,
    setValue,
    watch,
  } = form;

  const capabilities = watch('capabilities');

  const capabilitiesQuery = useQuery(
    appsKeys.instanceAvailableCapabilities(instance?.id!),
    () => getAvailableCapabilities({ id: instance?.id! }),
    {
      select: ({ data }) => {
        return formatCapabilitiesQuery(data);
      },
      onSuccess: ({ data }) => {
        reset({ capabilities: data });
      },
    },
  );

  const capabilitiesData = capabilitiesQuery.data?.data || {};

  const { modal: documentsOrderModal, showModal: showDocumentsOrderModal } =
    useModal(DocumentsOrder, { maxWidth: 'sm', fullWidth: true });

  const {
    modal: acknowledgementsConfigurationModal,
    showModal: showAcknowledgementsConfigurationModal,
  } = useModal(AcknowledgementsConfiguration, {
    maxWidth: 'sm',
    fullWidth: true,
  });

  const {
    modal: vacationsConfigurationModal,
    showModal: showVacationsConfigurationModal,
  } = useModal(VacationsConfiguration, { maxWidth: 'sm', fullWidth: true });

  const {
    modal: chatsConfigurationModal,
    showModal: showChatsConfigurationModal,
  } = useModal(ChatsConfiguration, { maxWidth: 'sm', fullWidth: true });

  const {
    modal: filesConfigurationModal,
    showModal: showFilesConfigurationModal,
  } = useModal(FilesConfiguration, { maxWidth: 'sm', fullWidth: true });

  const {
    modal: learningConfigurationModal,
    showModal: showLearningConfigurationModal,
  } = useModal(LearningConfiguration, { maxWidth: 'sm', fullWidth: true });

  const { modal: validateOrgModal, showModal: showValidateOrgModal } = useModal(
    ValidateOrgModal,
    { maxWidth: 'sm', fullWidth: true },
  );

  const handleChangeCapabilities = (
    event: ChangeEvent<HTMLInputElement>,
    checked: boolean,
  ) => {
    const { name } = event.target;

    const updatedCapabilities = formatCapabilitiesChange(
      capabilities,
      event.target,
    );

    setValue('capabilities', updatedCapabilities, { shouldDirty: true });

    if (name === UserPermissions.VIEW_ORGANIZATION_CHARTS && checked) {
      showValidateOrgModal({ form, onlyValidation: false });
    }
  };

  const handleSwitcherChange = (
    capability: UserPermissions,
    checked: boolean,
  ) => {
    const event = {
      target: {
        name: capability,
        checked,
      },
    } as React.ChangeEvent<HTMLInputElement>;
    handleChangeCapabilities(event, checked);
  };

  const updateCapabilitiesMutation = useMutation(
    () => updateInstance(instance?.id!, formatCapabilitiesData(capabilities)),
    {
      onSuccess: () => {
        enqueueSnackbar({ title: t('UPDATED_SUCCESS'), variant: 'success' });
        capabilitiesQuery.refetch();
        setLogEventApps(loggedUser, instance, capabilitiesData, capabilities);
      },
    },
  );

  const handleSaveCapabilities = handleSubmit(async () => {
    if (!capabilitiesQuery.isSuccess) {
      enqueueSnackbar({
        title: t('ERROR_LOADING_CAPABILITIES'),
        variant: 'error',
      });
      return;
    }
    await updateCapabilitiesMutation.mutateAsync();
  });

  const intersectionPermissions = useMemo(() => {
    if (!capabilitiesQuery.data) return [];

    const enhancedCapabilities = {
      ...capabilitiesData,
      ...(canLiveStreaming && { [UserPermissions.VIEW_LIVESTREAM]: true }),
      ...(canPayrollMobilityAdo && {
        [UserPermissions.VIEW_PAYROLL_MOBILITY_ADO]: true,
      }),
      ...(employeeLifecycleEnabled && {
        [UserPermissions.VIEW_EMPLOYEE_LIFECYCLE]: true,
      }),
    };

    return intersection(
      Object.keys(enhancedCapabilities),
      getModulesPermissions({
        canLiveStreaming,
        canPayrollMobilityAdo,
        employeeLifecycleEnabled,
        chatV1Enabled,
      }),
    )
      .filter(capability => !DELETED_CAPABILITIES.includes(capability))
      .sort((a, b) => {
        const titleA =
          HARDCODED_CAPABILITY_TITLES[a as UserPermissions] ??
          t('TITLE', { context: a });
        const titleB =
          HARDCODED_CAPABILITY_TITLES[b as UserPermissions] ??
          t('TITLE', { context: b });
        return titleA.localeCompare(titleB);
      }) as UserPermissions[];
  }, [
    capabilitiesQuery,
    capabilitiesData,
    t,
    canLiveStreaming,
    canPayrollMobilityAdo,
    employeeLifecycleEnabled,
  ]);

  const handleOpenSettings = (key: OpenSettings) => setOpenSettings(key);
  const handleCloseSettings = () => setOpenSettings(OpenSettings.NONE);

  const getCapabilityTitle = useCustomServerTranslation();

  const getCapabilityAction = (
    capability: UserPermissions,
  ): IconButtonProps | null => {
    let title = 'SETTINGS';
    let onClick = null;
    let disabled = false;
    let icon: ReactNode | null = <IconSettings />;

    // Backend does not support the config capability on CHATS_V2
    const CHAT_PERMISSIONS = chatV1Enabled
      ? UserPermissions.VIEW_REGULAR_CHATS
      : false;

    switch (capability) {
      case UserPermissions.VIEW_GROUPS:
        onClick = () => handleOpenSettings(OpenSettings.GROUPS);
        break;
      case UserPermissions.VIEW_BIRTHDAYS:
        title = 'SET_TIME';
        onClick = () => handleOpenSettings(OpenSettings.BIRTHDAY);
        break;
      case UserPermissions.VIEW_DOCUMENT:
        onClick = () => showDocumentsOrderModal();
        break;
      case UserPermissions.VIEW_ORGANIZATION_CHARTS:
        title = 'VALIDATE_ORG';
        onClick = () => showValidateOrgModal({ form, onlyValidation: true });
        icon = capabilities[capability] ? <IconProgressCheck /> : null;
        break;
      case UserPermissions.ACCESS_ACKNOWLEDGEMENTS:
        onClick = () => showAcknowledgementsConfigurationModal();
        break;
      case UserPermissions.VIEW_VACATIONS:
        onClick = () => showVacationsConfigurationModal();
        break;
      case CHAT_PERMISSIONS:
        onClick = () => showChatsConfigurationModal();
        break;
      case UserPermissions.VIEW_POSTS:
        onClick = () => handleOpenSettings(OpenSettings.FEED);
        break;
      case UserPermissions.VIEW_KNOWLEDGE_LIBRARIES:
        onClick = () => handleOpenSettings(OpenSettings.KNOWLEDGE_LIBRARIES);
        disabled = !capabilities[UserPermissions.VIEW_KNOWLEDGE_LIBRARIES];
        break;
      case UserPermissions.VIEW_FILE:
        onClick = () => showFilesConfigurationModal();
        break;
      case UserPermissions.VIEW_LEARNING:
        onClick = () => showLearningConfigurationModal();
        disabled = !capabilities[UserPermissions.VIEW_LEARNING];
        break;
      default:
        return null;
    }
    return {
      onClick,
      title: t(title),
      disabled,
      children: icon,
    };
  };

  const getSettingsDrawerProps = (key: OpenSettings) => ({
    handleSave: handleSaveCapabilities,
    onClose: handleCloseSettings,
    open: openSettings === key,
  });

  return (
    <>
      <FormProvider {...form}>
        {learningConfigurationModal}
        <FeedSettingsDrawer {...getSettingsDrawerProps(OpenSettings.FEED)} />
        <BirthdaySettingsDrawer
          {...getSettingsDrawerProps(OpenSettings.BIRTHDAY)}
        />
        <KnowledgeLibrariesSettingsDrawer
          {...getSettingsDrawerProps(OpenSettings.KNOWLEDGE_LIBRARIES)}
        />
        <GroupsSettingsDrawer
          {...getSettingsDrawerProps(OpenSettings.GROUPS)}
        />
      </FormProvider>
      {documentsOrderModal}
      {validateOrgModal}
      {acknowledgementsConfigurationModal}
      {vacationsConfigurationModal}
      {chatsConfigurationModal}
      {filesConfigurationModal}
      <Stack
        sx={{
          mx: '10%',
          mt: 6,
          backgroundColor: theme.palette.new.background.layout.default,
          minHeight: '100%',
        }}
      >
        <Title
          variant="L"
          sx={{
            animation: `${appearFromBottom} 100ms ease-in-out backwards`,
            fontWeight: 'fontWeightSemiBold',
            maxWidth: '1024px',
            marginInline: 'auto',
            width: '100%',
            mb: 3,
          }}
          title={t('APPS')}
          description={t('APPS_SUBTITLE')}
        />
        <Stack
          sx={{
            animation: `${appearFromBottom} 100ms ease-in-out backwards`,
            minHeight: '100%',
            maxWidth: '1024px',
            marginInline: 'auto',
            gap: 2,
            display: 'grid',
            gridTemplateColumns: 'repeat(12, 1fr)',
            width: '100%',
          }}
        >
          {capabilitiesQuery.isLoading &&
            Array.from({ length: 6 }).map((_, index) => (
              <Stack
                key={'skeleton-' + index}
                sx={{
                  gridColumn: 'span 12',
                  [theme.breakpoints.up('md')]: {
                    gridColumn: 'span 6',
                  },
                }}
              >
                <Skeleton
                  variant="rounded"
                  height={80}
                />
              </Stack>
            ))}
          {!capabilitiesQuery.isLoading &&
            intersectionPermissions.map(
              (capability: UserPermissions, index: number) => (
                <Stack
                  key={capability}
                  sx={{
                    animation: `${appearFromBottom} 125ms ease-in-out backwards`,
                    animationDelay: `${index * 15}ms`,
                    gridColumn: 'span 12',
                    [theme.breakpoints.up('md')]: {
                      gridColumn: 'span 6',
                    },
                  }}
                >
                  <AvatarSwitcherCard
                    key={capability}
                    sx={{
                      height: '100%',
                    }}
                    title={
                      HARDCODED_CAPABILITY_TITLES[capability] ??
                      getCapabilityTitle(
                        capabilityToi18nKey(capability),
                        'TITLE_' + capability,
                      )
                    }
                    description={
                      HARDCODED_CAPABILITY_DESCRIPTIONS[capability] ??
                      (HARDCODED_CAPABILITY_TITLES[capability]
                        ? ''
                        : t('DESCRIPTION', { context: capability }))
                    }
                    icon={getCapabilityIcon(capability)}
                    checked={!!capabilities[capability]}
                    onChange={checked =>
                      handleSwitcherChange(capability, checked)
                    }
                    pills={getCapabilityPills(capability, t)}
                    actions={
                      [getCapabilityAction(capability)].filter(
                        Boolean,
                      ) as IconButtonProps[]
                    }
                  />
                </Stack>
              ),
            )}
        </Stack>
      </Stack>
      <Stack
        sx={{
          mt: 6,
          py: 2,
          px: '15%',
          position: 'sticky',
          bottom: 0,
          alignItems: 'flex-end',
          backgroundColor: theme.palette.new.background.layout.tertiary,
          boxShadow: theme.shadows[2],
        }}
      >
        <Button
          variant="primary"
          size="large"
          onMouseDown={handleSaveCapabilities}
          loading={isSubmitting}
          disabled={!isDirty}
          sx={{ minWidth: 200 }}
        >
          {t('SAVE')}
        </Button>
      </Stack>
    </>
  );
};
export default CapabilitiesList;
