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

import { DEMAND_TAG_PAGE, SOURCE_TAG_OPTIONS, SUPPLY_TAG_PAGE } from '../../constants';
import { PCN_GET_MARKETPLACE_DASHBOARD } from '@/modules/@common/acl/constants';

import * as selectors from '../selectors';
import { getDataForWaterfallAction, setModalInfoAction } from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import { hasPermission } from '@/modules/@common/user/helpers';
import { getUserPermissionsSelector, getUserTimezoneSelector } from '@/modules/@common/user/redux/selectors';

export default (action$, state$) =>
  action$.pipe(
    ofType(getDataForWaterfallAction.type),
    debounce((action) => timer(action.payload.debounce ? 1000 : 0)),
    switchMap(({ payload: { page, rowsPerPage, config } }) => {
      const timezone = getUserTimezoneSelector(state$.value);
      const userPermissions = getUserPermissionsSelector(state$.value);
      const isAdminMP = hasPermission(PCN_GET_MARKETPLACE_DASHBOARD, userPermissions);

      const state = state$.value;

      const pageConfig = selectors.pageConfigSelector(state);
      const filterByDate = selectors.filterByDateSelector(state);
      const info = selectors.infoSelector(state);
      const userHubs = selectors.userHubsSelector(state);
      const userDemandAccounts = selectors.userDemandAccountsSelector(state);
      const modal = selectors.modalSelector(state);

      const { search, status, account, rate, model, label, displayType } = modal;

      const { change, dimension, changeDimension, ...range } = filterByDate;
      let filters = {
        source: SOURCE_TAG_OPTIONS[0].value,
      };

      if (dimension) {
        filters = {
          ...filters,
          dimension,
        };
      }

      if (change) {
        filters = {
          ...filters,
          changeRanges: [{ ...change, timezone }],
        };
      }

      if (changeDimension) {
        filters = {
          ...filters,
          changeDimension,
        };
      }

      if (info?.format) {
        filters = {
          ...filters,
          format: info.format,
        };
      }

      let mainParams = {
        fields: config.fields,
        size: rowsPerPage || 25,
        from: (page || 0) * (rowsPerPage || 25),
        filters: {
          ranges: [
            {
              ...range,
              timezone,
            },
          ],
          ...filters,
        },
      };

      if (search?.length) {
        mainParams = {
          ...mainParams,
          filters: {
            ...mainParams.filters,
            query: search,
          },
        };
      }

      if (status && status?.value !== 'ALL') {
        mainParams = {
          ...mainParams,
          filters: {
            ...mainParams.filters,
            status: { value: status.value },
          },
        };
      }

      if (pageConfig.type === SUPPLY_TAG_PAGE) {
        mainParams = {
          ...mainParams,
          filters: {
            ...mainParams.filters,
            supplyId: {
              exclude: true,
              value: pageConfig.id,
            },
          },
        };

        if (info?.publisherDemand) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              publisherDemand: info?.publisherDemand,
            },
          };
        }

        if (account) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              daccountIds: [
                {
                  value: account.id,
                },
              ],
            },
          };
        }

        if (label?.value) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              labels: [label.value],
            },
          };
        }

        if (rate?.length) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              pricing: {
                from: rate,
              },
            },
          };
        }

        if (model?.value) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              model: {
                value: model.value,
              },
            },
          };
        }

        if (!isAdminMP) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              daccountIds: userDemandAccounts.map((item) => ({ value: item.id?.toString() })),
            },
          };
        }
      }

      if (pageConfig.type === DEMAND_TAG_PAGE) {
        mainParams = {
          ...mainParams,
          filters: {
            ...mainParams.filters,
            demandId: {
              exclude: true,
              value: pageConfig.id,
            },
          },
        };

        if (info?.publisherDemand === false) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              publisherDemand: info?.publisherDemand,
            },
          };
        }

        if (account) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              accountIds: [
                {
                  value: account.id,
                },
              ],
            },
          };
        }

        if (!isAdminMP) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              siteIds: userHubs.map((item) => ({ value: item.id?.toString() })),
            },
          };
        }

        if (displayType) {
          mainParams = {
            ...mainParams,
            filters: {
              ...mainParams.filters,
              displayType: displayType.value,
            },
          };
        }
      }

      const stream$ = gqlRequest({
        query: config.query,
        variables: {
          ...mainParams,
        },
      }).pipe(
        switchMap((response) => {
          let actions = [];
          const { errors, data: waterfallData } = response;

          const tagData = {
            ...waterfallData.supplyTagData,
            ...waterfallData.demandTagData,
          };

          if (!errors.length) {
            actions = [
              of(
                setModalInfoAction({
                  data: tagData.data,
                  totalCount: tagData.totalCount,
                }),
              ),
            ];
          }

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

      return concat(
        of(setModalInfoAction({ isFetchingData: true })),
        stream$,
        of(setModalInfoAction({ isFetchingData: false })),
      );
    }),
  );
