import * as tableUtils from '../../commons/table';
import { sanitize } from '../../commons/text';
import { getExplicitRole } from '../../commons/aria';

function thHasDataCellsEvaluate(node) {
  const cells = tableUtils.getAllCells(node);
  const checkResult = this;

  // Get a list of all headers reffed to in this rule
  let reffedHeaders = [];
  cells.forEach(cell => {
    const headers = cell.getAttribute('headers');
    if (headers) {
      reffedHeaders = reffedHeaders.concat(headers.split(/\s+/));
    }

    const ariaLabel = cell.getAttribute('aria-labelledby');
    if (ariaLabel) {
      reffedHeaders = reffedHeaders.concat(ariaLabel.split(/\s+/));
    }
  });

  // Get all the headers
  const headers = cells.filter(cell => {
    if (sanitize(cell.textContent) === '') {
      return false;
    }
    return (
      cell.nodeName.toUpperCase() === 'TH' ||
      ['rowheader', 'columnheader'].indexOf(getExplicitRole(cell)) !== -1
    );
  });

  const tableGrid = tableUtils.toGrid(node);

  let out = true;
  headers.forEach(header => {
    if (
      header.getAttribute('id') &&
      reffedHeaders.includes(header.getAttribute('id'))
    ) {
      return;
    }

    const pos = tableUtils.getCellPosition(header, tableGrid);

    // ensure column header has at least 1 non-header cell and that the cell is
    // not pointing to a different header
    let hasCell = false;
    if (tableUtils.isColumnHeader(header)) {
      hasCell = tableUtils
        .traverse('down', pos, tableGrid)
        .find(
          cell =>
            !tableUtils.isColumnHeader(cell) &&
            tableUtils.getHeaders(cell, tableGrid).includes(header)
        );
    }

    // ensure row header has at least 1 non-header cell and that the cell is not
    // pointing to a different header
    if (!hasCell && tableUtils.isRowHeader(header)) {
      hasCell = tableUtils
        .traverse('right', pos, tableGrid)
        .find(
          cell =>
            !tableUtils.isRowHeader(cell) &&
            tableUtils.getHeaders(cell, tableGrid).includes(header)
        );
    }

    // report the node as having failed
    if (!hasCell) {
      checkResult.relatedNodes(header);
    }

    out = out && hasCell;
  });

  return out ? true : undefined;
}

export default thHasDataCellsEvaluate;
