import dayjs from 'dayjs';
import type {
  ChartPoint,
  CombinedDataType,
  Dataset,
  FlattenDataType,
  GroupedDataType,
} from './types';
import { groups } from 'd3-array';
// import { MIN_PLACEHOLDERS_COUNT } from './constants';

// export const getMinMaxDate = (data: ChartPoint[], type = 'min'): Date => {
//   const dateType = type === 'min' ? 'isBefore' : 'isAfter';
//
//   if (!data.length) return new Date();
//
//   const minMaxPoint = data.reduce(
//     (a: ChartPoint, b: ChartPoint): ChartPoint =>
//       dayjs(a.x)[dateType](dayjs(b.x)) ? a : b
//   );
//   return minMaxPoint?.x;
// };

export const getMaxYValue = (data: ChartPoint[] = []): number => {
  const maxPoint = data.reduce(
    (acc: ChartPoint, b: ChartPoint): ChartPoint => (acc.y > b.y ? acc : b)
  );
  const [item1, item2] = data;
  // @ts-ignore
  const diff = item1?.y - item2?.y;

  return maxPoint?.y + (diff || 1);
};

export const getXLabelsInterval = (totalXGraphCount: number): number => {
  let xGraphInterval = 1;
  if (totalXGraphCount >= 14) {
    xGraphInterval = 2;
  }
  return xGraphInterval;
};

export const convertDataArrToObj = (
  data: ChartPoint[],
  dateFormat = 'MMM DD'
) => {
  return data.reduce((acc: Object, usage: ChartPoint) => {
    // @ts-ignore
    acc[dayjs(usage.date).format(dateFormat)] = usage.value;
    return acc;
  }, {});
};

export const getYLabels = (maxValue: number): Array<string | number> => {
  const fiveArr = Array.from(Array(5).keys());
  return fiveArr
    .map((item: number) => {
      if (item === 4) {
        return Number(maxValue.toFixed(1));
      }
      if (item === 0) return 0;
      return Math.floor((maxValue / 4) * item);
    })
    .reverse();
};

const getXLabelDate = (date: Date, isDateHidden: boolean) =>
  isDateHidden ? '--' : dayjs(date).format('D');
export const getXLabel = ({
  idx,
  date,
  totalCount,
  xLabelsInterval,
  chartType = 'line',
}: {
  idx: number;
  date: Date;
  totalCount: number;
  xLabelsInterval: number;
  chartType?: 'line' | 'bar';
}) => {
  const isDateHidden = chartType === 'bar' && dayjs(date).isAfter(dayjs());

  if (xLabelsInterval === 1) {
    return getXLabelDate(date, isDateHidden);
  }

  // here we want to keep the first and the last date of the cycle
  //  but exclude the second and the last but one
  if (idx === 0 || idx === totalCount - 1) {
    return getXLabelDate(date, isDateHidden);
  } else if (idx % xLabelsInterval && idx !== 1 && idx !== totalCount - 2) {
    return getXLabelDate(date, isDateHidden);
  } else {
    return '';
  }
};

// this function is taken from d3-array
// https://github.com/d3/d3-array/blob/main/src/max.js
export default function d3Max(
  values: ChartPoint[],
  valueof: ((arg0: any, arg1: number, arg2: any) => any) | undefined
) {
  let max;
  if (valueof === undefined) {
    for (const value of values) {
      if (
        value != null &&
        // @ts-ignore todo: fix types
        (max < value || (max === undefined && value >= value))
      ) {
        max = value;
      }
    }
  } else {
    let index = -1;
    for (let value of values) {
      if (
        (value = valueof(value, ++index, values)) != null &&
        // @ts-ignore todo: fix types
        (max < value || (max === undefined && value >= value))
      ) {
        max = value;
      }
    }
  }
  return max;
}

// // sample of PoolLineDailyUsageFormatted:
// //   {"date": "2022-09-16", "18931943440": 0.08, "3576721372": 0.1}
// export type PoolLineDailyUsageFormatted = {
//   date: Date | string;
//   // mdn: usage of the line
//   // ...
// };
//
// // export const getKeysForBarChart = (poolLineDailyUsage: PoolLineDailyUsageFormatted[]) => {
// //   return Object.keys(omit(poolLineDailyUsage[0], 'date'));
// // };
// //
// // export const getBarChartPlaceholders = (
// //   usageArr: PoolLineDailyUsageFormatted[],
// //   cycleStartDate: Date,
// // ) => {
// //   const totalCount = usageArr.length;
// //   if (totalCount >= MIN_PLACEHOLDERS_COUNT) return usageArr;
// //
// //   if (usageArr.length) {
// //     const lastUsageItem = usageArr[usageArr.length - 1];
// //     let mostRecentDate = dayjs(lastUsageItem.date);
// //     const nextUsagePlaceholders = [...usageArr];
// //
// //     for (let i = totalCount; i < MIN_PLACEHOLDERS_COUNT; i++) {
// //       const nextDate = dayjs(mostRecentDate).add(1, 'day');
// //       nextUsagePlaceholders.push({ date: nextDate });
// //       mostRecentDate = nextDate;
// //     }
// //
// //     return nextUsagePlaceholders;
// //   } else {
// //     // if there is no any usages of any line -> return placeholders array...
// //     //  which is dates array starting from the cycleStartDate
// //     return Array(MIN_PLACEHOLDERS_COUNT)
// //       .fill(0)
// //       .map((_, idx: number) => ({ date: dayjs(cycleStartDate).add(idx, 'day') }));
// //   }
// // };

// todo: fix types
export const getDataToStack = (datasets: Dataset[]): CombinedDataType[] => {
  const flattenData = datasets.flatMap((dataset) => {
    return dataset.data.map((dataPoint) => {
      return {
        date: new Date(dataPoint.x),
        [dataset.label]: Number(dataPoint.y),
      };
    });
  });

  const groupedData: GroupedDataType[] = groups(
    flattenData,
    (d: FlattenDataType) => d.date
  );

  const combinedData: CombinedDataType[] = groupedData.map(([_, data]) => {
    return Object.assign({}, ...data);
  });

  const sortedData = combinedData.sort((a, b) => {
    return new Date(a.date).getTime() - new Date(b.date).getTime();
  });
  return sortedData;
};
