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

import { GET_ACCOUNT } from '@/graphql/services/accounts/constants';
import { TYPE_ERROR } from '@/modules/@common/notify/constants';

import { PAYLOAD_NAME } from '@/graphql/services/accounts/types/payload/account';

import { getItemAction, setAction } from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import { showNotificationAction } from '@/modules/layout/redux/slices';

const queryItem = `
  query ${GET_ACCOUNT}($payload: ${PAYLOAD_NAME}) {
    ${GET_ACCOUNT}(payload: $payload) {
      salesforceInstanceUrl
      salesforceId
      name
      publisherDemand
      adServingFeeBusinessModel
      adServingFeeDisplay
      adServingFeeVideo
      salesManager
      accountManager
      accountManagerEmail
      type
      avatarUrl
      customLogoUrl
      customLoadingMessage
      customLoginPageUrl
      subdomain
      publisherRevShare
      expenses
      usersLimit
      videoDuplicatesBy
      accountsFeatures {
        value
        accountsFeatures {
          blockedByFeature
          category
          defaultValue
          featureTooltipText
          id
          name
          noFlagOff
          order
          status
          title
        }
      }
      accountDashboards {
        general {
          id
          uiName
          enabled
          order
          tooltip {
            info
            link
            linkTitle
          }
        }
        custom {
          id
          uiName
          enabled
          order
          lookerReportId
          icon
          publisherCustomAnalytics {
            accountId
            action
            id
            publisherId
            publisherIds
          }
        }
      }
    }
  }
`;

const queryFeature = `
  query ${GET_ACCOUNT}($payload: ${PAYLOAD_NAME}) {
    ${GET_ACCOUNT}(payload: $payload) {
      salesforceInstanceUrl
      accountsFeatures {
        value
        accountsFeatures {
          blockedByFeature
          category
          defaultValue
          featureTooltipText
          id
          name
          noFlagOff
          order
          status
          title
        }
      }
    }
  }
`;

// shape is [{ categoryName: 'featureCategoryName', features: [{ObjectOfFeature}] }]
function transformFeaturesToUiShape(data) {
  const accountsFeatures = data
    .filter((item) => !!item.accountsFeatures.status)
    .map((item) => item.accountsFeatures || [])
    .sort((a, b) => a.order - b.order);

  const groupedByCategory = accountsFeatures.reduce((acc, feature) => {
    const { category } = feature;
    if (!acc[category]) {
      acc[category] = { categoryName: category, features: [feature] };
    } else {
      acc[category].features.push(feature);
    }
    return acc;
  }, {});

  return Object.values(groupedByCategory).map((group) => ({
    ...group,
  }));
}

// shape for form data is { featureId1: featureValue1, etc }
function transformFeaturesToDataShape(data) {
  return Object.fromEntries(data.map(({ accountsFeatures: { id }, value }) => [id, value]));
}

// shape for related filed { featureId1: featureId2, etc }.
// That means when featureId1 eq false need to disable featureId2
function transformFeaturesToDependFieldShape(data) {
  const depend = data.map((feature) => {
    const dependField = data.find(
      (entity) => entity.accountsFeatures.blockedByFeature === feature.accountsFeatures.name,
    );
    return [feature.accountsFeatures.id, dependField?.accountsFeatures.id];
  });
  return Object.fromEntries(depend);
}

const getResponse = ({ data }) => {
  const account = data[GET_ACCOUNT];

  return {
    ...account,
  };
};

export default (action$) =>
  action$.pipe(
    ofType(getItemAction.type),
    switchMap((action) => {
      const stream$ = gqlRequest(
        {
          query: action.payload === 'new' ? queryFeature : queryItem,
          variables: {
            payload: {
              id: action.payload,
            },
          },
        },
        {
          showNotificationMessage: false,
        },
      ).pipe(
        switchMap((response) => {
          const actions = [];

          if (response.errors.length) {
            actions.push(
              of(
                showNotificationAction({
                  type: TYPE_ERROR,
                  message: "Can't open account for edit",
                }),
              ),
            );

            Router.push('/accounts');
          } else {
            const { accountsFeatures, accountDashboards, ...data } = getResponse(response);

            const featuresUi = transformFeaturesToUiShape(accountsFeatures);
            const featuresData = transformFeaturesToDataShape(accountsFeatures);
            const featuresDependsFieldData = transformFeaturesToDependFieldShape(accountsFeatures);

            const dashboardsGeneral = accountDashboards?.general?.sort((a, b) => a.order - b.order) || [];
            const dashboardsCustom = accountDashboards?.custom?.sort((a, b) => a.order - b.order) || [];

            actions.push(
              of(
                setAction({
                  ...data,
                  featuresUi,
                  featuresData,
                  featuresDependsFieldData,
                  dashboardsGeneral,
                  dashboardsCustom,
                }),
              ),
            );
          }

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

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