import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector, useStore } from 'react-redux';
import { useRouter } from 'next/router';

import {
  PCN_POST_PLAYER_NEW,
  PCN_PUT_PLAYER_NEW,
  SELF_SERV_PLAYER_ACCESS_MONETIZATION,
} from '@/modules/@common/acl/constants';
import {
  TYPE_INTELLIGENT,
  TYPE_INTELLIGENT_AMP,
  TYPE_OUTSTREAM,
  TYPE_STORIES,
  TYPE_STORIES_AMP,
  TYPE_VERTICAL,
} from '@/modules/@common/constants/playerTypes';
import { TYPE_ERROR } from '@/modules/@common/notify/constants';
import {
  CONTENT_FILTERS_TAB,
  CUSTOM_PLACEHOLDER_TAB,
  DISPLAY_ADS_TAB,
  FLOATING_TAB,
  GENERAL_TAB,
  INACTIVATED_PLAYER,
  LOOK_AND_FEEL_TAB,
  PLAYBACK_TAB,
  UNSUPPORTED_PLAYER_TYPE,
  VIDEO_ADS_TAB,
} from '@/modules/players/Editor/constants';
import { PLAYER_TYPES } from '@/modules/players/Players/constants';

import * as playerSelectors from '../redux/selectors';
import { isNumber } from '@/modules/@common/helpers/number';
import { hasPermission } from '@/modules/@common/user/helpers';
import { getUserAccountSelector, getUserPermissionsSelector } from '@/modules/@common/user/redux/selectors';
import { showNotificationAction } from '@/modules/layout/redux/slices';
import { isAmpTypes, isOutstreamType } from '@/modules/players/Editor/helpers';
import {
  createPlayerAction,
  getPlayerDataAction,
  setAction,
  setActiveTabIdAction,
  setErrorByPropAction,
  setInitialAction,
  setScrollToFieldNameAction,
  updatePlayerAction,
  validateFields,
} from '@/modules/players/Editor/redux/slices';

import { Form, FormContent, FormSection } from '@/modules/@common/Form';
import SaveAndCreateTagsConfirmDialog from '@/modules/players/Editor/components/SaveAndCreateTagsConfirmDialog/SaveAndCreateTagsConfirmDialog';
import PlayerPreviewWrapper from '@/modules/players/Editor/components/Tabs/PlayerPreviewWrapper';
import ContentFiltersTab from './Tabs/ContentFiltersTab/ContentFiltersTab';
import CustomPlaceholderTab from './Tabs/CustomPlaceholderTab/CustomPlaceholderTab';
import DisplayAdsTab from './Tabs/DisplayAdsTab/DisplayAdsTab';
import FloatingTab from './Tabs/FloatingTab/FloatingTab';
import GeneralTab from './Tabs/GeneralTab/GeneralTab';
import LookAndFeelTab from './Tabs/LookAndFeelTab/LookAndFeelTab';
import PlaybackTab from './Tabs/PlaybackTab/PlaybackTab';
import VideoAdsTab from './Tabs/VideoAdsTab/VideoAdsTab';
import { Button, Stack, Tab, TabContent, Tabs, Tooltip, Typography } from '@/mui/components';

import styles from './Editor.module.scss';

function Editor() {
  const [open, setOpen] = useState(false);
  const [saveAndCreateTagsDialogOpen, setSaveAndCreateTagsDialogOpen] = useState(false);
  const store = useStore();
  const dispatch = useDispatch();
  const router = useRouter();

  const publisher = useSelector(playerSelectors.publisherSelector);
  const playerType = useSelector(playerSelectors.playerTypeSelector);
  const isLoading = useSelector(playerSelectors.isLoadingSelector);
  const abTest = useSelector(playerSelectors.abTestSelector);
  const status = useSelector(playerSelectors.statusSelector);

  const userPermissions = useSelector(getUserPermissionsSelector);

  const activeTabId = useSelector(playerSelectors.activeTabIdSelector);
  const alias = useSelector(playerSelectors.aliasSelector);
  const availablePlayerTypes = useSelector(playerSelectors.availableTemplatePlayersSelector);

  const userAccount = useSelector(getUserAccountSelector);

  const canCreatePlayer = hasPermission(PCN_POST_PLAYER_NEW, userPermissions);
  const canUpdatePlayer = hasPermission(PCN_PUT_PLAYER_NEW, userPermissions);
  const accessMonetization = hasPermission(SELF_SERV_PLAYER_ACCESS_MONETIZATION, userPermissions);

  const paramTypeId = parseInt(router.query.params[0], 10) || null;
  const id = parseInt(router.query.params[1], 10) || null;
  const paramPlayerType = PLAYER_TYPES.find((type) => type.id === paramTypeId && type.selfServe);
  const copyFromId = parseInt(router.query.copy, 10) || null;
  const canReadOnly = (id && !canUpdatePlayer) || (!id && !canCreatePlayer);

  const shouldShowSaveAndCreateTagsBtn =
    [TYPE_INTELLIGENT, TYPE_INTELLIGENT_AMP, TYPE_OUTSTREAM, TYPE_STORIES, TYPE_STORIES_AMP, TYPE_VERTICAL].includes(
      paramTypeId,
    ) &&
    !canReadOnly &&
    !id &&
    isNumber(userAccount.expenses) &&
    isNumber(userAccount.publisherRevShare);

  const tabs = [
    {
      label: 'General',
      Content: GeneralTab,
      id: GENERAL_TAB,
      show: true,
    },
    {
      label: 'Look & Feel',
      Content: LookAndFeelTab,
      id: LOOK_AND_FEEL_TAB,
      show: paramTypeId !== TYPE_OUTSTREAM,
    },
    {
      label: 'Floating',
      Content: FloatingTab,
      id: FLOATING_TAB,
      show: true,
    },
    {
      label: 'Content Filters',
      Content: ContentFiltersTab,
      id: CONTENT_FILTERS_TAB,
      show: paramTypeId !== TYPE_OUTSTREAM,
    },
    {
      label: 'Playback',
      Content: PlaybackTab,
      id: PLAYBACK_TAB,
      show: paramTypeId !== TYPE_OUTSTREAM,
    },
    {
      label: 'Video Ads',
      Content: VideoAdsTab,
      id: VIDEO_ADS_TAB,
      show: !!publisher?.monetization && accessMonetization,
    },
    {
      label: 'Display Overlay Ads',
      Content: DisplayAdsTab,
      id: DISPLAY_ADS_TAB,
      show: paramTypeId !== TYPE_OUTSTREAM && !!publisher?.monetization && accessMonetization,
    },
    {
      label: 'Custom Placeholder',
      Content: CustomPlaceholderTab,
      id: CUSTOM_PLACEHOLDER_TAB,
      show: true,
    },
  ].filter(({ show }) => show);

  const validate = () => {
    const state = store.getState();
    const allProps = playerSelectors.fullAccessToStoreFieldsForValidation(state);
    const isAmp = isAmpTypes(allProps.playerType?.id);
    const isOutstream = isOutstreamType(allProps.playerType?.id);

    const { validation, errorList } = validateFields(
      playerSelectors
        .schemeSelector(state)
        .filter(({ tabId }) => tabs.some((tab) => tab.id === tabId))
        .filter(({ fieldName }) => {
          // omit for floating tab those fields
          if (['floatingDesktopDelay', 'floatingMobileDelay'].includes(fieldName)) {
            return !isAmp && !isOutstream;
          }
          if (fieldName === 'selectors') {
            return allProps.customPlaceholderEnable;
          }
          return true;
        })
        .map(({ fieldName }) => fieldName),
      allProps,
    );

    const errorFields = errorList.map((field) => {
      if (['playerWidth', 'playerWidthMobile'].includes(field.fieldName)) {
        return {
          ...field,
          tabId: isOutstreamType(playerType?.id) ? GENERAL_TAB : LOOK_AND_FEEL_TAB,
        };
      }
      return field;
    });

    if (errorFields.length) {
      const errorField = errorFields.find((error) => error.tabId === activeTabId) ?? errorFields[0];

      dispatch(setActiveTabIdAction(errorField.tabId));
      dispatch(setScrollToFieldNameAction(errorField.fieldName));
    }

    dispatch(setErrorByPropAction(validation));

    return { errorFields };
  };

  const handleSave = () => {
    const { errorFields } = validate();

    if (!errorFields.length) {
      if (id) {
        dispatch(updatePlayerAction());
      } else {
        dispatch(createPlayerAction({ copyFromId, shouldCreateTags: false }));
      }
    }
  };

  const handleSaveAndCreateTags = () => {
    const { errorFields } = validate();

    if (!errorFields.length) {
      setSaveAndCreateTagsDialogOpen(true);
    }
  };

  useEffect(() => {
    if (
      !paramPlayerType ||
      (playerType && playerType.id !== paramTypeId) ||
      (!id &&
        !copyFromId &&
        availablePlayerTypes?.length &&
        !availablePlayerTypes.some((type) => type.id === paramTypeId))
    ) {
      dispatch(
        showNotificationAction({
          key: UNSUPPORTED_PLAYER_TYPE,
          type: TYPE_ERROR,
          message: UNSUPPORTED_PLAYER_TYPE,
        }),
      );
      router.replace('/player');
    }
  }, [paramTypeId, playerType, availablePlayerTypes]);

  useEffect(() => {
    if (id && status < 1) {
      dispatch(
        showNotificationAction({
          key: INACTIVATED_PLAYER,
          type: TYPE_ERROR,
          message: INACTIVATED_PLAYER,
        }),
      );
      router.replace('/player');
    }
  }, [id, status]);

  useEffect(() => {
    if (!id && !copyFromId && paramPlayerType) {
      dispatch(
        setAction({
          playerType: paramPlayerType,
          type: paramPlayerType.id,
        }),
      );
    }
    dispatch(getPlayerDataAction({ id: copyFromId || id, copy: !!copyFromId }));
  }, [id, paramTypeId, copyFromId]);

  useEffect(() => () => dispatch(setInitialAction()), []);

  const shouldHavePreview = PLAYER_TYPES.find((type) => type.id === paramTypeId && type.preview);

  const playerPreview = useMemo(
    () =>
      publisher && shouldHavePreview ? (
        <FormSection>
          <PlayerPreviewWrapper />
        </FormSection>
      ) : null,
    [publisher, shouldHavePreview],
  );

  const getTitle = () => {
    let action = 'New';
    let suffix = 'Player';

    if (copyFromId) {
      action = 'Copy';
    } else if (id) {
      action = `${alias}`;
      suffix = '> Settings';
    }

    return `${action} ${playerType?.name || ''} ${suffix}`;
  };

  return (
    <div className={styles.Wrapper}>
      <Stack direction="column" fullWidth justifyContent="center" className={styles.Title}>
        <Typography component="div" variant="h6" noWrap>
          {getTitle()}
        </Typography>
      </Stack>
      <Stack
        spacing={1}
        fullWidth
        direction="row"
        alignItems="center"
        justifyContent="space-between"
        className={styles.Controls}
      >
        {tabs.length > 1 && (
          <Tabs
            size="medium"
            orientation="horizontal"
            value={activeTabId}
            className={styles.Tabs}
            onChange={(event, value) => {
              dispatch(
                setAction({
                  activeTabId: value,
                }),
              );
            }}
          >
            {tabs.map((tab) => (
              <Tab key={tab.id} label={tab.label} value={tab.id} />
            ))}
          </Tabs>
        )}
        <Stack spacing={2} justifyContent="flex-end" alignItems="center" direction="row">
          <Button
            variant="outlined"
            size="small"
            color="primary"
            shape="rounded"
            onClick={() => router.push('/player')}
          >
            Cancel
          </Button>
          {!canReadOnly && (
            <Tooltip
              open={open && abTest}
              placement="bottom"
              disableFocusListener
              disableTouchListene
              title="The player cannot be updated because an active A/B test is applied.
                  Please contact your Account Manager for more details."
            >
              <span
                onMouseEnter={() => setOpen(true)} // Manually control open state
                onMouseLeave={() => setOpen(false)}
              >
                <Button
                  disabled={isLoading || abTest}
                  variant="contained"
                  size="small"
                  color="primary"
                  shape="rounded"
                  onClick={handleSave}
                >
                  Save
                </Button>
              </span>
            </Tooltip>
          )}
          {shouldShowSaveAndCreateTagsBtn && (
            <Button
              disabled={isLoading}
              variant="contained"
              size="small"
              color="primary"
              shape="rounded"
              onClick={handleSaveAndCreateTags}
            >
              Save & Create Tags
            </Button>
          )}
        </Stack>
      </Stack>
      <Form scrollFieldSelector={playerSelectors.scrollFieldSelector}>
        {tabs.map((tab) => {
          const { Content } = tab;

          return (
            <TabContent key={tab.id} selectedId={activeTabId} id={tab.id} component={FormContent}>
              <Content playerPreview={playerPreview} />
            </TabContent>
          );
        })}
      </Form>

      {saveAndCreateTagsDialogOpen && (
        <SaveAndCreateTagsConfirmDialog
          open={saveAndCreateTagsDialogOpen}
          onClose={() => setSaveAndCreateTagsDialogOpen(false)}
          onConfirm={() => {
            dispatch(createPlayerAction({ copyFromId, shouldCreateTags: true }));
            setSaveAndCreateTagsDialogOpen(false);
          }}
        />
      )}
    </div>
  );
}

export default Editor;
