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_ACCOUNTS_PAGE_TYPE, SUPPLY_ACCOUNTS_PAGE_TYPE } from '../../constants';
import { PCN_GET_MARKETPLACE_DASHBOARD } from '@/modules/@common/acl/constants';

import * as selectors from '../selectors';
import {
  getAccountsAction,
  refreshPageDataByIntervalAction,
  saveToCSVAction,
  setActiveTabIndexAction,
  setFieldAction,
  setFilterByStatusAction,
  setFilterDateAction,
  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,
  setFilterDateAction.type,
  setSortByAction.type,
  setSortOrderAction.type,
  setRowsPerPageAction.type,
  setActiveTabIndexAction.type,
  setFilterByStatusAction.type,
  setFilterFormatAction.type,
];

export default (action$, state$) =>
  action$.pipe(
    ofType(
      getAccountsAction.type,
      setSearchAction.type,
      setFilterDateAction.type,
      setSortByAction.type,
      setSortOrderAction.type,
      setRowsPerPageAction.type,
      refreshPageDataByIntervalAction.type,
      setActiveTabIndexAction.type,
      setFilterByStatusAction.type,
      setFilterFormatAction.type,
    ),
    filter(() => {
      const userPermissions = getUserPermissionsSelector(state$.value);
      const state = state$.value;

      const pageConfig = selectors.pageConfigSelector(state);
      const userDemandAccounts = selectors.userDemandAccountsSelector(state);
      const isAdminMP = hasPermission(PCN_GET_MARKETPLACE_DASHBOARD, userPermissions);

      if (!isAdminMP) {
        return !!userDemandAccounts?.length;
      }

      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 filterDate = selectors.filterDateSelector(state);
      const filterByStatus = selectors.filterByStatusSelector(state);
      const page = selectors.pageSelector(state);
      const rowsPerPage = selectors.rowsPerPageSelector(state);
      const activeTabIndex = selectors.activeTabIndexSelector(state);
      const userDemandAccounts = selectors.userDemandAccountsSelector(state);
      const userHubs = selectors.userHubsSelector(state);

      const formatFilter = formatFilterSelector(state);

      const timezone = getUserTimezoneSelector(state$.value);

      const { isCustomPeriod, ...filterDateRest } = filterDate;
      const { change, dimension, changeDimension, ...range } = filterDateRest;
      let currentPage = page;
      let filters = {};

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

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

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

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

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

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

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

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

      if (!isAdminMP && pageConfig?.type === SUPPLY_ACCOUNTS_PAGE_TYPE) {
        filters = {
          ...filters,
          siteIds: userHubs.filter((item) => item.mpSelfService).map((item) => ({ value: item.id?.toString() })),
        };
      }

      const tabs = isAdminMP ? pageConfig.tabs : pageConfig.selfServeTabs;
      const fields = isAdminMP
        ? tabs[activeTabIndex].fields
        : tabs[activeTabIndex].fields.filter((item) => item !== 'PROFIT');

      const stream$ = gqlRequest({
        query: tabs[activeTabIndex].graphQuery,
        variables: {
          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,
        },
      }).pipe(
        switchMap(({ data, errors }) => {
          let actions = [];
          const accountsData = {
            ...data.supplyAccountsData,
            ...data.demandAccountsData,
            ...data.siteData,
            ...data.supplyTagData,
            ...data.demandTagData,
            ...data.advertiserData,
          };

          if (!errors.length) {
            const dataWithTime = [
              ...accountsData.data.map((item) => ({
                ...item,
                fields: {
                  ...item?.fields,
                  REQUESTS: {
                    ...item?.fields?.REQUESTS,
                    // todo: it has to be split and replaced
                    apsInfo: !!(item?.hasApsTags || item?.aps),
                    // mark requests cell red if profit false (advertisers and demand tag tables)
                    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({
                    data: dataWithTime || [],
                    isAdminMP,
                  }),
                ),
              ];
            } else {
              actions = [
                of(setFieldAction({ accounts: dataWithTime || [] })),
                of(setFieldAction({ totalCount: accountsData.totalCount })),
                of(setFieldAction({ page: currentPage })),
              ];
            }
          }

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

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