import * as React from 'react';
import { ColumnProps } from './interface';

export function flatArray(data: any[] = [], childrenName = 'children') {
  const result: any[] = [];
  const loop = (array: any[]) => {
    array.forEach(item => {
      if (item[childrenName]) {
        const newItem = { ...item };
        delete newItem[childrenName];
        result.push(newItem);
        if (item[childrenName].length > 0) {
          loop(item[childrenName]);
        }
      } else {
        result.push(item);
      }
    });
  };
  loop(data);
  return result;
}

export function treeMap<Node>(tree: Node[], mapper: (node: Node, index: number) => any, childrenName = 'children') {
  return tree.map((node: any, index) => {
    const extra: any = {};
    if (node[childrenName]) {
      extra[childrenName] = treeMap(node[childrenName], mapper, childrenName);
    }
    return {
      ...mapper(node as Node, index),
      ...extra,
    };
  });
}

export function flatFilter<T>(tree: ColumnProps<T>[], callback: (node: ColumnProps<T>) => any): ColumnProps<T>[] {
  return tree.reduce((acc, node) => {
    if (callback(node)) {
      acc.push(node);
    }
    if (node.children) {
      const children = flatFilter(node.children, callback);
      acc.push(...children);
    }
    return acc;
  }, [] as ColumnProps<T>[]);
}

export function normalizeColumns(elements: React.ReactChildren) {
  const columns: any[] = [];
  React.Children.forEach(elements, (element) => {
    if (!React.isValidElement(element)) {
      return;
    }
    const column: any = {
      ...element.props,
    };
    if (element.key) {
      column.key = element.key;
    }
    if (element.type && (element.type as any).__ANT_TABLE_COLUMN_GROUP) {
      column.children = normalizeColumns(column.children);
    }
    columns.push(column);
  });
  return columns;
}

export function getLeafColumns<T>(columns: ColumnProps<T>[]) {
  return flatFilter(columns, c => !c.children);
}

export function findColumnByFilterValue<T>(record: T, columns: ColumnProps<T>[], inputValue: string): ColumnProps<T> | undefined {
  return columns.find((col) => {
    const key = getColumnKey(col);
    if (key) {
      let value = (record as any)[key];
      if (value) {
        value = value.toString();
        if (value.toLowerCase().indexOf(inputValue.toLowerCase()) !== -1) {
          return true;
        }
      }
    }
    return false;
  });
}

export function filterByInputValue<T>(dataSource: T[],
                                      columns: ColumnProps<T>[],
                                      inputValue: string,
                                      cb: (record: T, column: ColumnProps<T>) => void) {
  dataSource.forEach((data) => {
    const column = findColumnByFilterValue<T>(data, columns, inputValue);
    if (column) {
      cb(data, column);
    }
  });
}

export function removeHiddenColumns<T>(columns: ColumnProps<T>[]) {
  return columns.filter(c => {
    if (c.hidden) {
      return false;
    } else if (c.children) {
      const children = removeHiddenColumns(c.children);
      if (children.length) {
        c.children = children;
      } else {
        return false;
      }
    }
    return true;
  });
}

export function getColumnKey<T>(column: ColumnProps<T>, index?: number) {
  return column.key || column.dataIndex || index;
}