import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import dayjs from 'dayjs';
import { useRouter } from 'next/router';
import { parse } from 'qs';
import { CloseRounded, DownloadRounded, TheatersRounded, TrendingUpRounded } from '@mui/icons-material';

import { PCN_GET_VIDEO, VIDEO_INSIGHTS } from '@/modules/@common/acl/constants';
import { TRENDING } from '@/modules/editorial/constants/video';
import {
  DEFAULT_EVERGREEN_TYPE_VALUE,
  DEFAULT_FEED_TYPE_VALUE,
  DEFAULT_PUBLISH_PLATFORM_TYPE_VALUE,
  DEFAULT_PUBLISH_STATUS_TYPE_VALUE,
  DEFAULT_VERIFICATION_TYPE_VALUE,
  DEFAULT_VIDEO_STATUS_VALUE,
  FEED_TYPE_VIDEO_AUDIO,
  namesFilterSelectors,
  SEARCH_PARAMS_TO_NOT_EXCLUDE,
  SPONSORED_ALL,
  VIDEO_TARGETING_ANY,
} from '@/modules/editorial/editorialSearchFilter/constants';

import { getFiltersNamesByPermission } from '../../helpers';
import * as selectors from '../redux/selectors';
import {
  configAction,
  configChangedEventAction,
  configCopyAction,
  isFilterDirtyAction,
  isInsightsModeAction,
  isMoreFiltersOpenedAction,
} from '../redux/slices';
import { deepClone, isEqual } from '@/modules/@common/helpers';
import { addQueriesAction } from '@/modules/@common/location/redux/slices';
import { hasPermission } from '@/modules/@common/user/helpers';
import {
  getUserContentOwnerIdsSelector,
  getUserPermissionsSelector,
  getUserRoleTypeSelector,
} from '@/modules/@common/user/redux/selectors';
import { isActiveSelector as isBulkActionsActiveSelector } from '@/modules/editorial/bulkActions/redux/selectors';
import { playlistTypeSelector } from '@/modules/editorial/editorialSearch/reduxSearch/selectors';
import { isVideosLoadingSelector } from '@/modules/editorial/editorialSearchResults/redux/selectors';
import { downloadEventAction } from '@/modules/editorial/editorialSearchResults/redux/slices';
import { getDefaultTabAfterSearchOrFilter, getVideoTabs } from '@/modules/editorial/helpers/videoTab';
import { aiPlaylistModeSelector } from '@/modules/editorial/RightSideBar/TabPlaylist/redux/selectors';
import { isMobileApp } from '@/modules/layout/helpers';

import BulkActionsPanelSuccess from '@/modules/editorial/bulkActions/components/BulkActionPanelSuccess/BulkActionPanelSuccess';
import BulkActionsPanel from '@/modules/editorial/bulkActions/components/BulkActionsPanel/BulkActionsPanel';
import VideoTabs from '@/modules/editorial/editorialSearchFilter/VideoTabs';
import AdditionalFilters from '../../additionalFilters/additionalFilters';
import {
  DEFAULT_FILTER_NAMES,
  filterConfig as defaultFilterConfig,
  getDefaultConfig,
  INSIGHTS_FILTER_NAMES,
} from '../../filterConfig';
import FilterItem from '../../filterItem/filterItem';
import { Box, Button, Stack, ToggleButton, ToggleButtonGroup, Tooltip } from '@/mui/components';

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

const VIDEOS_MODE = 'videos';
const INSIGHTS_MODE = 'insights';

const getFiltersFromURL = (search, config, userRoleType, userPermissions) => {
  // if there no filters queries in the URL return default
  if (search && (!Object.keys(search).length || !Object.keys(search).filter((key) => config[key]).length)) {
    return config;
  }

  return Object.keys(search)
    .filter((key) => {
      const filterNames = getFiltersNamesByPermission(false, userRoleType, userPermissions).concat(
        SEARCH_PARAMS_TO_NOT_EXCLUDE,
      );

      return filterNames.includes(key);
    })
    .reduce(
      (acc, cur) => {
        if (acc[cur]) {
          const filters = acc[cur].filters[0];

          // for additionalFilters, when value is array
          if (Array.isArray(filters?.value) && cur === 'uploadDate') {
            return {
              ...acc,
              [cur]: {
                ...acc[cur],
                filters: [
                  {
                    ...filters,
                    value: [
                      {
                        from: search[cur][0].from ? +search[cur][0].from : null,
                        to: search[cur][0].to ? +search[cur][0].to : null,
                      },
                    ],
                  },
                ],
              },
            };
          }

          if (
            cur === 'videoTabs' &&
            !getVideoTabs(userPermissions)
              .map((tab) => tab.value)
              .includes(search[cur])
          ) {
            return {
              ...acc,
              [cur]: {
                ...acc[cur],
                filters: [
                  {
                    ...filters,
                    value: getDefaultTabAfterSearchOrFilter(userPermissions).value,
                  },
                ],
              },
            };
          }

          // for custom time with datepicker
          if (cur === 'time' && (search[cur]?.startDate || search[cur]?.endDate)) {
            return {
              ...acc,
              [cur]: {
                ...acc[cur],
                filters: [
                  {
                    label: 'Custom',
                    value: {
                      startDate: dayjs(+(search[cur]?.startDate ?? 0))
                        .toDate()
                        .getTime(),
                      endDate: dayjs(+(search[cur]?.endDate ?? 0))
                        .toDate()
                        .getTime(),
                    },
                  },
                ],
              },
            };
          }

          if (Array.isArray(filters?.value) || namesFilterSelectors.includes(cur)) {
            const currentOption = filters.options ? filters.options.find(({ value }) => value === search[cur]) : null;

            return {
              ...acc,
              [cur]: {
                ...acc[cur],
                filters: [
                  {
                    ...filters,
                    value: namesFilterSelectors.includes(cur) ? [currentOption] : search[cur],
                  },
                ],
              },
            };
          }

          const newFilter = defaultFilterConfig[cur]?.filters?.find(
            (filter) => filter.value === search[cur] || filter.value === search[cur]?.value,
          );

          const newFilters = [
            {
              ...filters,
              ...newFilter,
            },
          ];

          // for order, that has isReversed additional key
          if (cur === 'order') {
            return {
              ...acc,
              [cur]: {
                ...acc[cur],
                filters: newFilters,
                isReversed: search[cur]?.isReversed === 'true',
              },
            };
          }

          return {
            ...acc,
            [cur]: {
              ...acc[cur],
              filters: newFilters,
            },
          };
        }

        return acc;
      },
      { ...config },
    );
};

function SearchFilterComponent(props) {
  const router = useRouter();
  const dispatch = useDispatch();
  const aiPlaylistMode = useSelector(aiPlaylistModeSelector);

  const userRoleType = useSelector(getUserRoleTypeSelector);
  const contentOwners = useSelector(getUserContentOwnerIdsSelector).map((id) => `${id}`);

  const userPermissions = useSelector(getUserPermissionsSelector);

  const playlistType = useSelector(playlistTypeSelector);

  const isVideosLoading = useSelector(isVideosLoadingSelector);

  const config = useSelector(selectors.configSelector);
  const tabCounters = useSelector(selectors.tabCountersSelector);
  const isFilterDirty = useSelector(selectors.isFilterDirtySelector);
  const isInsightsMode = useSelector(selectors.isInsightsModeSelector);
  const isMoreFiltersOpened = useSelector(selectors.isMoreFiltersOpenedSelector);

  const isBulkActionsActive = useSelector(isBulkActionsActiveSelector);

  const handleFilterItemClick = (filter, update, isTrending) => (value) => {
    const videoTab = getDefaultTabAfterSearchOrFilter(userPermissions);
    const {
      orderForInsights: defaultOrderForInsights,
      timeFrame: defaultTimeFrame,
      videoTabs: defaultVideoTabs,
      ...defaultConfigOrderless
    } = getDefaultConfig();

    const updatedConfig = deepClone({
      ...config,
      [filter]: {
        ...config[filter],
        filters: [value],
      },
      videoTabs: { filters: [videoTab] },
    });

    const {
      orderForInsights: updatedOrderForInsights,
      timeFrame: updatedTimeFrame,
      videoTabs,
      ...updatedConfigOrderless
    } = updatedConfig;

    dispatch(isFilterDirtyAction(!isEqual(updatedConfigOrderless, defaultConfigOrderless)));

    if (isTrending) {
      updatedConfig.order.filters[0] = {
        label: 'Trending',
        value: 'trending',
        isSortable: false,
      };
    }

    dispatch(configAction(updatedConfig));

    if (update) {
      dispatch(configChangedEventAction());
    }

    dispatch(addQueriesAction({ videoTabs: videoTab?.value }));

    if (!aiPlaylistMode) {
      dispatch(configCopyAction(deepClone(updatedConfig)));
    }
  };
  const handleFilterItemSortIconClick = (filter) => () => {
    const updatedConfig = {
      ...config,
      [filter]: {
        ...config[filter],
        isReversed: !config[filter].isReversed,
      },
    };

    dispatch(configAction(updatedConfig));
    dispatch(configChangedEventAction());
  };
  const handleClearAllFilters = () => {
    const defaultConfig = {
      ...getDefaultConfig(),
      videoTabs: config.videoTabs,
    };

    const resultConfig = Object.keys(defaultConfig).reduce(
      (acc, key) => ({
        ...acc,
        ...{
          [key]: {
            ...defaultConfig[key],
            filters: [defaultConfig[key].filters[0]],
          },
        },
      }),
      {},
    );
    dispatch(configAction(resultConfig));
    dispatch(configChangedEventAction());
    dispatch(isFilterDirtyAction(false));
  };

  const handleApplyAdditionalFilters = () => {
    dispatch(configChangedEventAction());

    if (!aiPlaylistMode) {
      dispatch(configCopyAction(deepClone(config)));
    }
  };

  const handleChangeMode = (isVideoMode) => {
    if (!isVideoMode) {
      props.setShowSideBar(false);
    }

    dispatch(isInsightsModeAction(!isVideoMode));

    if (isVideoMode && config.orderForInsights.filters.length) {
      dispatch(
        configAction({
          ...config,
          orderForInsights: {
            ...config.orderForInsights,
            filters: [],
            isReversed: false,
          },
        }),
      );
      dispatch(configChangedEventAction());
    }
  };

  useEffect(() => {
    const updatedConfig = {
      ...config,
    };

    const decoded = parse(router.asPath.split('?')[1], {
      ignoreQueryPrefix: true,
      // this func need to decode "false", "true" like boolean
      decoder(str, decoder, charset) {
        const strWithoutPlus = str.replace(/\+/g, ' ');
        if (charset === 'iso-8859-1') {
          // unescape never throws, no try...catch needed:
          return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape);
        }

        // parse numbers
        // if (/^(\d+|\d*\.\d+)$/.test(str)) {
        //   return parseFloat(str);
        // }

        const keywords = {
          true: true,
          false: false,
          null: null,
          undefined,
        };

        if (str in keywords) {
          return keywords[str];
        }

        // utf-8
        try {
          return decodeURIComponent(strWithoutPlus);
        } catch {
          return strWithoutPlus;
        }
      },
    });

    const newConfig = getFiltersFromURL(decoded, updatedConfig, userRoleType, userPermissions);

    const { videoTabs: videoTabsDefault, ...defaultConfigOrderless } = getDefaultConfig();
    const { videoTabs, ...updatedConfigOrderless } = newConfig;

    if (Object.prototype.hasOwnProperty.call(decoded, 'orderForInsights')) {
      dispatch(isInsightsModeAction(true));
      props.setShowSideBar(false);
    }

    dispatch(isFilterDirtyAction(!isEqual(updatedConfigOrderless, defaultConfigOrderless)));

    dispatch(configAction(newConfig));
    dispatch(configChangedEventAction());
  }, []);

  const selectedItemsCount = getFiltersNamesByPermission(false, userRoleType, userPermissions).reduce((acc, key) => {
    const filterValue = config[key]?.filters[0]?.value;
    const isFilterIsActive =
      !!filterValue.length && filterValue[0] !== undefined && !!filterValue.map((item) => item?.value).length;

    const accVal = (defaultVal) => (filterValue[0]?.value !== defaultVal ? 1 : 0);

    switch (key) {
      case 'evergreen':
        return acc + accVal(DEFAULT_EVERGREEN_TYPE_VALUE);
      case 'feedType':
        return acc + accVal(DEFAULT_FEED_TYPE_VALUE);
      case 'mediaType':
        return acc + accVal(FEED_TYPE_VIDEO_AUDIO);
      case 'sponsored':
        return acc + accVal(SPONSORED_ALL);
      case 'status':
        return acc + accVal(DEFAULT_VIDEO_STATUS_VALUE);
      case 'verification':
        return acc + accVal(DEFAULT_VERIFICATION_TYPE_VALUE);
      case 'publishStatus':
        return acc + accVal(DEFAULT_PUBLISH_STATUS_TYPE_VALUE);
      case 'publishPlatform':
        return acc + accVal(DEFAULT_PUBLISH_PLATFORM_TYPE_VALUE);
      case 'uploadDate':
        return acc + (filterValue[0].from !== null || filterValue[0].to !== null ? 1 : 0);
      case 'targetingStatus':
        return acc + accVal(VIDEO_TARGETING_ANY);
      default:
        return acc + (isFilterIsActive ? 1 : 0);
    }
  }, 0);

  const filterConfig = {
    ...defaultFilterConfig,
    order: {
      ...defaultFilterConfig.order,
    },
  };

  const canDownload = hasPermission(PCN_GET_VIDEO, userPermissions);

  useEffect(() => {
    const { watchId } = router.query;

    if (watchId) {
      dispatch(isMoreFiltersOpenedAction(false));
    }
  }, [router.asPath]);

  return (
    <div data-id="searchFilterComponent" className={styles.Container}>
      <div data-id="filterBar" className={styles.FilterBar}>
        <Stack spacing={1} direction="row" alignItems="center" className={styles.Filters}>
          {Object.keys(DEFAULT_FILTER_NAMES).map(
            (key) =>
              (config[key]?.isMobile || !isMobileApp) && (
                <Box key={key} onClick={() => dispatch(isMoreFiltersOpenedAction(false))}>
                  <FilterItem
                    type={key}
                    filters={filterConfig[key].filters}
                    selected={config[key].filters}
                    handleClick={handleFilterItemClick(key, true)}
                    onSortIconClick={handleFilterItemSortIconClick(key)}
                    {...filterConfig[key]}
                    isReversed={config[key].isReversed}
                    disabled={key === 'order' && isInsightsMode}
                  />
                </Box>
              ),
          )}
          <div>
            <Button
              size="small"
              variant="outlined"
              color={isMoreFiltersOpened || !!selectedItemsCount ? 'primary' : 'neutral'}
              onClick={() => dispatch(isMoreFiltersOpenedAction(!isMoreFiltersOpened))}
            >
              More Filters
              {!!selectedItemsCount && <b className={styles.Count}>{selectedItemsCount}</b>}
            </Button>
          </div>
        </Stack>
        <Stack spacing={2} direction="row" alignItems="center" justifyContent="flex-end">
          {isFilterDirty && !isMobileApp && (
            <div>
              <Button variant="text" size="small" startIcon={<CloseRounded />} onClick={handleClearAllFilters}>
                Reset Filters
              </Button>
            </div>
          )}
          {isInsightsMode && (
            <div data-id="insights-filters">
              {Object.keys(INSIGHTS_FILTER_NAMES).map(
                (key) =>
                  (config[key]?.isMobile || !isMobileApp) && (
                    <div
                      role="button"
                      tabIndex={0}
                      onKeyUp={null}
                      onClick={() => dispatch(isMoreFiltersOpenedAction(false))}
                      key={key}
                      data-id={`insights-filter-${key}`}
                    >
                      <FilterItem
                        key={key}
                        type={key}
                        filters={filterConfig[key].filters}
                        selected={config[key].filters}
                        handleClick={handleFilterItemClick(key, true)}
                        onSortIconClick={handleFilterItemSortIconClick(key)}
                        {...filterConfig[key]}
                        isReversed={config[key].isReversed}
                      />
                    </div>
                  ),
              )}
            </div>
          )}

          {!isMobileApp && (
            <Stack direction="row" alignItems="center" spacing={2}>
              {hasPermission(VIDEO_INSIGHTS, userPermissions) && (
                <ToggleButtonGroup
                  value={isInsightsMode ? INSIGHTS_MODE : VIDEOS_MODE}
                  exclusive
                  color="neutral"
                  size="small"
                  onChange={(event, newState) => handleChangeMode(newState === VIDEOS_MODE)}
                >
                  {[
                    {
                      id: VIDEOS_MODE,
                      title: 'Videos',
                      icon: TheatersRounded,
                    },
                    {
                      id: INSIGHTS_MODE,
                      title: 'Insights',
                      icon: TrendingUpRounded,
                    },
                  ].map((button) => {
                    const Icon = button.icon;

                    return (
                      <ToggleButton key={button.id} value={button.id}>
                        <Tooltip title={button.title}>
                          <Icon />
                        </Tooltip>
                      </ToggleButton>
                    );
                  })}
                </ToggleButtonGroup>
              )}
              {!isInsightsMode && canDownload && (
                <Tooltip title="Export Video List">
                  <Button
                    disabled={!!isVideosLoading}
                    size="small"
                    color="neutral"
                    variant="outlined"
                    square
                    startIcon={<DownloadRounded />}
                    onClick={(v) => dispatch(downloadEventAction(v))}
                  />
                </Tooltip>
              )}
            </Stack>
          )}
        </Stack>
        <AdditionalFilters
          keys={getFiltersNamesByPermission(aiPlaylistMode, userRoleType, userPermissions)}
          config={config}
          filterConfig={filterConfig}
          contentOwners={contentOwners}
          isOpened={isMoreFiltersOpened}
          isTrending={playlistType === TRENDING && aiPlaylistMode}
          isFilterDirty={isFilterDirty}
          setOpen={(v) => dispatch(isMoreFiltersOpenedAction(v))}
          handleClick={handleFilterItemClick}
          handleReset={handleClearAllFilters}
          handleApply={() => handleApplyAdditionalFilters()}
        />
      </div>
      {!isBulkActionsActive && (
        <VideoTabs
          currentFilterConfig={config}
          tabCounters={tabCounters}
          setFilter={(v) => dispatch(configAction(v))}
          applyFilter={(v) => dispatch(configChangedEventAction(v))}
        />
      )}

      {isBulkActionsActive && <BulkActionsPanel />}

      <BulkActionsPanelSuccess />
    </div>
  );
}

SearchFilterComponent.propTypes = {
  setShowSideBar: PropTypes.func.isRequired,
};

export default SearchFilterComponent;
