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

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

import { addPageParams } from '../../helpers/filters';
import * as selectors from '../selectors';
import {
  getDataAction,
  refreshPageDataByIntervalAction,
  saveToCSVAction,
  setFieldAction,
  setFilterByCountryAction,
  setFilterByDateAction,
  setFilterByDeviceAction,
  setFilterByLabelAction,
  setFilterByPlayerAction,
  setFilterByStatusAction,
  setRowsPerPageAction,
  setSearchAction,
  setSortByAction,
  setSortOrderAction,
} from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import { hasPermission } from '@/modules/@common/user/helpers';
import { getUserPermissionsSelector, getUserTimezoneSelector } from '@/modules/@common/user/redux/selectors';
import { formatFilterSelector } from '@/modules/marketplace/dashboard/redux/selectors';
import { setFilterFormatAction } from '@/modules/marketplace/dashboard/redux/slices';

const actionsWithRefresh = [
  setSearchAction.type,
  setFilterByDateAction.type,
  setSortByAction.type,
  setSortOrderAction.type,
  setRowsPerPageAction.type,
  setFilterByStatusAction.type,
  setFilterByCountryAction.type,
  setFilterByDeviceAction.type,
  setFilterByPlayerAction.type,
  setFilterByLabelAction.type,
  setFilterFormatAction.type,
];

export default (action$, state$) =>
  action$.pipe(
    ofType(
      getDataAction.type,
      setSearchAction.type,
      setFilterByDateAction.type,
      setSortByAction.type,
      setSortOrderAction.type,
      setRowsPerPageAction.type,
      setFilterByStatusAction.type,
      setFilterByCountryAction.type,
      setFilterByDeviceAction.type,
      setFilterByPlayerAction.type,
      setFilterByLabelAction.type,
      refreshPageDataByIntervalAction.type,
      setFilterFormatAction.type,
    ),
    filter(() => {
      const state = state$.value;

      const pageConfig = selectors.pageConfigSelector(state);

      return !!pageConfig;
    }),
    debounce((action) => timer(action.type === setSearchAction.type ? 1000 : 0)),
    switchMap(({ type, payload }) => {
      const state = state$.value;

      const userPermissions = getUserPermissionsSelector(state$.value);
      const isAdminMP = hasPermission(PCN_GET_MARKETPLACE_DASHBOARD, userPermissions);

      const pageConfig = selectors.pageConfigSelector(state);
      const search = selectors.searchSelector(state);
      const sortBy = selectors.sortBySelector(state);
      const sortOrder = selectors.sortOrderSelector(state);
      const filterByDate = selectors.filterByDateSelector(state);
      const filterByStatus = selectors.filterByStatusSelector(state);
      const page = selectors.pageSelector(state);
      const rowsPerPage = selectors.rowsPerPageSelector(state);
      const filterByCountry = selectors.filterByCountrySelector(state);
      const filterByDevice = selectors.filterByDeviceSelector(state);
      const filterByPlayer = selectors.filterByPlayerSelector(state);
      const filterByLabel = selectors.filterByLabelSelector(state);

      const formatFilter = formatFilterSelector(state);

      const timezone = getUserTimezoneSelector(state);

      const { isCustomPeriod, ...filterByDateRest } = filterByDate;
      const { change, dimension, changeDimension, ...range } = filterByDateRest;
      let filters = {};

      let currentPage = page;

      if (actionsWithRefresh.includes(type)) {
        currentPage = 0;
      }

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

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

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

      if (formatFilter && !(pageConfig?.type === DEMAND_TAG_PAGE || pageConfig?.type === SUPPLY_TAG_PAGE)) {
        filters = {
          ...filters,
          ...formatFilter,
        };
      }

      if (pageConfig?.type === SUPPLY_SITE_PAGE && filterByCountry) {
        filters = {
          ...filters,
          geo: filterByCountry,
        };
      }

      if (pageConfig?.type === SUPPLY_SITE_PAGE && filterByDevice) {
        filters = {
          ...filters,
          device: filterByDevice,
        };
      }

      if (pageConfig?.type === SUPPLY_SITE_PAGE && filterByPlayer?.value) {
        filters = {
          ...filters,
          widgetId: filterByPlayer.value,
        };
      }

      if (pageConfig?.type === DEMAND_ADVERTISER_PAGE && filterByLabel) {
        filters = {
          ...filters,
          labels: [filterByLabel.value],
        };
      }

      const fields = isAdminMP ? pageConfig.dataFields : pageConfig.dataFields.filter((item) => item !== 'PROFIT');

      let mainParams = {
        fields,
        size: payload?.allPages ? 1000 : rowsPerPage || 25,
        from: payload?.allPages ? 0 : (currentPage || 0) * (rowsPerPage || 25),
        sort: {
          [LIST_OF_META_SORTING.includes(sortBy) ? 'ofMeta' : 'of']: sortBy,
          order: sortOrder,
        },
        filters: {
          ranges: [
            {
              ...range,
              timezone,
            },
          ],
          ...filters,
        },
        allPages: !!payload?.allPages,
      };

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

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

      const params = addPageParams(mainParams, pageConfig, isAdminMP, true);

      const stream$ = gqlRequest({
        query: pageConfig.dataQuery,
        variables: {
          ...params,
        },
      }).pipe(
        switchMap(({ data = {}, errors }) => {
          let actions = [];
          const accountData = {
            ...data.siteData,
            ...data.supplyTagData,
            ...data.demandTagData,
            ...data.demandTagDataSelfServeCompressed,
            ...data.advertiserData,
          };

          if (!errors.length) {
            const dataWithTime = [
              ...accountData.data.map((item) => ({
                ...item,
                fields: {
                  ...item?.fields,
                  REQUESTS: {
                    ...item?.fields?.REQUESTS,
                    // todo: it has to be split and replaced
                    apsInfo: pageConfig.type !== DEMAND_ADVERTISER_PAGE && !!(item?.hasApsTags || item?.aps),
                    // mark requests cell red if profit false (advertiser, demand tag pages)
                    profitDecreased: item?.profit === false,
                  },
                },
                created: item?.created ? dayjs(+item.created).tz(timezone).format('YYYY/MM/DD h:mm A') : null,
              })),
            ];

            if (payload?.allPages) {
              actions = [of(saveToCSVAction(dataWithTime || []))];
            } else {
              actions = [
                of(setFieldAction({ data: dataWithTime || [] })),
                of(setFieldAction({ totalCount: accountData.totalCount })),
                of(setFieldAction({ page: currentPage })),
              ];
            }
          }

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

      return concat(of(setFieldAction({ isLoading: true })), stream$, of(setFieldAction({ isLoading: false })));
    }),
  );
