import dayjs from 'dayjs';
import { type Epic } from 'redux-observable';
import { concat, defer, of } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';
import type { Action } from '@reduxjs/toolkit';

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

import { type DataRecordType } from '../../types';

import * as selectors from '../selectors';
import { exportToCsvAction } from '../slices';
import { saveBlobAsFile } from '@/modules/@common/helpers/file-saver';
import { getUserTimezoneSelector } from '@/modules/@common/user/redux/selectors';
import { showNotificationAction } from '@/modules/layout/redux/slices';

type Header = {
  label: string;
  id: keyof DataRecordType;
};

const epic: Epic<Action, Action, RootState> = (action$, state$) =>
  action$.pipe(
    filter(
      (action): action is ReturnType<typeof exportToCsvAction> =>
        action.type === exportToCsvAction.type && !!selectors.dataSelector(state$.value)?.length,
    ),
    switchMap(() => {
      const state = state$.value;
      const userTimezone = getUserTimezoneSelector(state$.value) ?? 'UTC';
      const data = selectors.dataSelector(state)!;

      const headers: Header[] = [
        {
          label: 'Date',
          id: 'time',
        },
        {
          label: 'Player Loads',
          id: 'playerLoads',
        },
        {
          label: 'Ad Impressions Video',
          id: 'videoAdImpressions',
        },
        {
          label: 'Ad Impressions Display',
          id: 'displayAdImpressions',
        },
        {
          label: 'Publisher Demand Revenue',
          id: 'publisherVideoRevenue',
        },
        {
          label: 'Anyclip Demand Revenue',
          id: 'anyclipVideoRevenue',
        },
        {
          label: 'Platform Fees',
          id: 'platformFee',
        },
        {
          label: 'Net Revenue',
          id: 'netRevenue',
        },
        {
          label: 'Player Loads RPM',
          id: 'rpm',
        },
      ];

      const dataCSV = [
        headers.map(({ label }) => label).join(','),
        ...data.map((obj, dataIndex) =>
          headers
            .map((h) => {
              let value = obj[h.id] ?? '';

              if (h.id === 'time') {
                value = value ? dayjs(value).tz(userTimezone).format('MMM D, YYYY hh:mm A') : '';

                if (dataIndex >= data.length - 1) {
                  value = 'Total';
                }
              } else if (h.id === 'publisherVideoRevenue') {
                value = (obj.publisherVideoRevenue || 0) + (obj.publisherDisplayRevenue || 0);
              } else if (h.id === 'anyclipVideoRevenue') {
                value = (obj.anyclipVideoRevenue || 0) + (obj.anyclipDisplayRevenue || 0);
              }

              return JSON.stringify(value);
            })
            .join(','),
        ),
      ].join('\n');

      const stream$ = defer(async () => {
        const JSZip = (await import('jszip')).default;

        const zip = new JSZip();
        zip.file('data.csv', dataCSV);

        return zip.generateAsync({ type: 'blob' });
      }).pipe(
        switchMap((content) => {
          saveBlobAsFile(content, `Revenue-overview.zip`);

          return concat(
            of(
              showNotificationAction({
                type: TYPE_SUCCESS,
                message: 'Download was successful',
              }),
            ),
          );
        }),
      );

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

export default epic;
