import { ofType } from 'redux-observable';
import { concat, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';

import { TYPE_SUCCESS } from '@/modules/@common/notify/constants';

import { aiPlaylistSelector } from '../selectors';
import { setAiFiltersAction, updateAiFiltersAction } from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import {
  filterParamsSelector,
  searchFiltersSelector,
} from '@/modules/editorial/editorialSearchResults/redux/selectors';
import { showNotificationAction } from '@/modules/layout/redux/slices';

import { timeMap } from '@/modules/editorial/editorialSearchFilter/filterConfig';

const queryGQL = `
  mutation createAiFilters(
    $watchId: Int!,
    $channelId: Int!,
    $aiPlaylistId: Int!,
    $filters: [AiFilter],
  ) {
    createAiFilters(
      watchId: $watchId,
      channelId: $channelId,
      aiPlaylistId: $aiPlaylistId,
      filters: $filters,
    ) {
      data {
        id
      }
    }
  }
`;

const INCLUDE = 'INCLUDE';
const EXCLUDE = 'EXCLUDE';

const acceptedParams = {
  iab: (filters) =>
    filters.map((param) => ({
      type: 'IAB',
      value: param,
      action: INCLUDE,
    })),
  iabExcludes: (filters) =>
    filters.map((param) => ({
      type: 'IAB',
      value: param,
      action: EXCLUDE,
    })),
  keywordFilters: (filters) =>
    filters.map((param) => ({
      type: param.category,
      value: param.keyword,
      action: INCLUDE,
    })),
  keywordExcludes: (filters) =>
    filters.map((param) => ({
      type: param.category,
      value: param.keyword,
      action: EXCLUDE,
    })),
  labelFilters: (filters) =>
    filters.map((param) => ({
      type: 'LABEL',
      value: `${param.name}:${param.value}`,
      color: param.color,
      action: INCLUDE,
      extra: param.labelId,
    })),
  labelExcludes: (filters) =>
    filters.map((param) => ({
      type: 'LABEL',
      value: `${param.name}:${param.value}`,
      color: param.color,
      action: EXCLUDE,
      extra: param.labelId,
    })),
  lang: (filters) =>
    filters.map((param) => ({
      type: 'LANG',
      value: param.toUpperCase(),
      action: INCLUDE,
    })),
  langExcludes: (filters) =>
    filters.map((param) => ({
      type: 'LANG',
      value: param.toUpperCase(),
      action: EXCLUDE,
    })),
  feedDescription: (filters) =>
    filters.map((param) => ({
      type: 'FEED',
      value: param,
      action: INCLUDE,
    })),
  feedDescriptionExcludes: (filters) =>
    filters.map((param) => ({
      type: 'FEED',
      value: param,
      action: EXCLUDE,
    })),
  evergreen: (filter) => [
    {
      type: 'EVERGREEN',
      value: filter.toString(),
      action: INCLUDE,
    },
  ],
  lengthFrom: (filter) => [
    {
      type: 'LENGTH_FROM',
      value: `${filter}`,
      action: INCLUDE,
    },
  ],
  lengthTo: (filter) => [
    {
      type: 'LENGTH_TO',
      value: `${filter}`,
      action: INCLUDE,
    },
  ],
  videoAffiliation: (filter) => [
    {
      type: 'VIDEO_AFFILIATION',
      value: filter,
      action: INCLUDE,
    },
  ],
  videoTab: (filter) => [
    {
      type: 'VIDEO_OWNERSHIP',
      value: filter,
      action: INCLUDE,
    },
  ],
  targetingStatus: (filter) => [
    {
      type: 'TARGETING_STATUS',
      value: filter,
      action: INCLUDE,
    },
  ],
  mediaType: (filter) => [
    {
      type: 'MEDIA_TYPE',
      value: filter,
      action: INCLUDE,
    },
  ],
};

export default (action$, state$) =>
  action$.pipe(
    ofType(updateAiFiltersAction.type),
    switchMap(({ payload: { watchId, channelId, aiPlaylistId } }) => {
      const aiPlaylists = aiPlaylistSelector(state$.value);
      const filterParams = filterParamsSelector(state$.value);
      const { time } = searchFiltersSelector(state$.value);

      const filtersToSend = Object.keys(filterParams)
        .filter((param) => Object.keys(acceptedParams).includes(param))
        .reduce((acc, cur) => [...acc, ...acceptedParams[cur](filterParams[cur])], []);

      if (timeMap[time.filters[0]?.value]) {
        filtersToSend.push({
          type: 'TIME',
          value: timeMap[time.filters[0].value],
          action: INCLUDE,
        });
      } else if (filterParams.startDate && filterParams.endDate) {
        const { startDate, endDate } = filterParams;
        filtersToSend.push(
          {
            type: 'START_DATE',
            value: startDate.toString(),
            action: INCLUDE,
          },
          {
            type: 'END_DATE',
            value: endDate.toString(),
            action: INCLUDE,
          },
        );
      }

      const stream$ = gqlRequest({
        query: queryGQL,
        variables: {
          watchId,
          channelId,
          aiPlaylistId,
          filters: filtersToSend.map((item) =>
            Object.keys(item).reduce((acc, key) => {
              if (key !== 'color') {
                acc[key] = item[key];
              }

              return acc;
            }, {}),
          ),
        },
      }).pipe(
        switchMap(({ errors }) => {
          const actions = [];

          if (!errors.length) {
            const playlistType = Object.keys(aiPlaylists).find((key) => aiPlaylists[key]?.id === aiPlaylistId);

            actions.push(
              of(
                setAiFiltersAction({
                  [playlistType]: [...filtersToSend],
                }),
              ),
              of(
                showNotificationAction({
                  type: TYPE_SUCCESS,
                  message: 'Filters saved',
                }),
              ),
            );
          }

          return concat(...actions);
        }),
      );

      return concat(stream$);
    }),
  );
