/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License;
 * you may not use this file except in compliance with the Elastic License.
 */

import { EuiButtonIcon, EuiLink } from '@elastic/eui';

import React from 'react';
import _ from 'lodash';

import { i18n } from '@kbn/i18n';

import {
  formatHumanReadableDate,
  formatHumanReadableDateTime,
  formatHumanReadableDateTimeSeconds,
} from '../../util/date_utils';

import { DescriptionCell } from './description_cell';
import { DetectorCell } from './detector_cell';
import { EntityCell } from '../entity_cell';
import { InfluencersCell } from './influencers_cell';
import { LinksMenu } from './links_menu';
import { checkPermission } from '../../privilege/check_privilege';
import { mlFieldFormatService } from '../../services/field_format_service';
import { isRuleSupported } from '../../../common/util/anomaly_utils';
import { formatValue } from '../../formatters/format_value';
import { INFLUENCERS_LIMIT, ANOMALIES_TABLE_TABS } from './anomalies_table_constants';
import { SeverityCell } from './severity_cell';

function renderTime(date, aggregationInterval) {
  if (aggregationInterval === 'hour') {
    return formatHumanReadableDateTime(date);
  } else if (aggregationInterval === 'second') {
    return formatHumanReadableDateTimeSeconds(date);
  } else {
    return formatHumanReadableDate(date);
  }
}

function showLinksMenuForItem(item, showViewSeriesLink) {
  const canConfigureRules = isRuleSupported(item.source) && checkPermission('canUpdateJob');
  return (
    canConfigureRules ||
    (showViewSeriesLink && item.isTimeSeriesViewRecord) ||
    item.entityName === 'mlcategory' ||
    item.customUrls !== undefined
  );
}

export function getColumns(
  items,
  jobIds,
  examplesByJobId,
  isAggregatedData,
  interval,
  timefilter,
  showViewSeriesLink,
  showRuleEditorFlyout,
  itemIdToExpandedRowMap,
  toggleRow,
  filter,
  influencerFilter
) {
  const columns = [
    {
      name: '',
      render: item => (
        <EuiButtonIcon
          onClick={() => toggleRow(item)}
          iconType={itemIdToExpandedRowMap[item.rowId] ? 'arrowDown' : 'arrowRight'}
          aria-label={
            itemIdToExpandedRowMap[item.rowId]
              ? i18n.translate('xpack.ml.anomaliesTable.hideDetailsAriaLabel', {
                  defaultMessage: 'Hide details',
                })
              : i18n.translate('xpack.ml.anomaliesTable.showDetailsAriaLabel', {
                  defaultMessage: 'Show details',
                })
          }
          data-row-id={item.rowId}
        />
      ),
    },
    {
      field: 'time',
      name: i18n.translate('xpack.ml.anomaliesTable.timeColumnName', {
        defaultMessage: 'time',
      }),
      dataType: 'date',
      render: date => renderTime(date, interval),
      textOnly: true,
      sortable: true,
    },
    {
      field: 'severity',
      name: i18n.translate('xpack.ml.anomaliesTable.severityColumnName', {
        defaultMessage: 'severity',
      }),
      render: (score, item) => (
        <SeverityCell score={score} multiBucketImpact={item.source.multi_bucket_impact} />
      ),
      sortable: true,
    },
    {
      field: 'detector',
      name: i18n.translate('xpack.ml.anomaliesTable.detectorColumnName', {
        defaultMessage: 'detector',
      }),
      render: (detectorDescription, item) => (
        <DetectorCell detectorDescription={detectorDescription} numberOfRules={item.rulesLength} />
      ),
      textOnly: true,
      sortable: true,
    },
  ];

  if (items.some(item => item.entityValue !== undefined)) {
    columns.push({
      field: 'entityValue',
      name: i18n.translate('xpack.ml.anomaliesTable.entityValueColumnName', {
        defaultMessage: 'found for',
      }),
      render: (entityValue, item) => (
        <EntityCell
          entityName={item.entityName}
          entityValue={entityValue}
          filter={filter}
          wrapText={true}
        />
      ),
      textOnly: true,
      sortable: true,
    });
  }

  if (items.some(item => item.influencers !== undefined)) {
    columns.push({
      field: 'influencers',
      name: i18n.translate('xpack.ml.anomaliesTable.influencersColumnName', {
        defaultMessage: 'influenced by',
      }),
      render: influencers => (
        <InfluencersCell
          limit={INFLUENCERS_LIMIT}
          influencers={influencers}
          influencerFilter={influencerFilter}
        />
      ),
      textOnly: true,
      sortable: true,
    });
  }

  // Map the additional 'sort' fields to the actual, typical and description
  // fields to ensure sorting is done correctly on the underlying metric value
  // and not on e.g. the actual values array as a String.
  if (items.some(item => item.actual !== undefined)) {
    columns.push({
      field: 'actualSort',
      name: i18n.translate('xpack.ml.anomaliesTable.actualSortColumnName', {
        defaultMessage: 'actual',
      }),
      render: (actual, item) => {
        const fieldFormat = mlFieldFormatService.getFieldFormat(
          item.jobId,
          item.source.detector_index
        );
        return formatValue(item.actual, item.source.function, fieldFormat, item.source);
      },
      sortable: true,
    });
  }

  if (items.some(item => item.typical !== undefined)) {
    columns.push({
      field: 'typicalSort',
      name: i18n.translate('xpack.ml.anomaliesTable.typicalSortColumnName', {
        defaultMessage: 'typical',
      }),
      render: (typical, item) => {
        const fieldFormat = mlFieldFormatService.getFieldFormat(
          item.jobId,
          item.source.detector_index
        );
        return formatValue(item.typical, item.source.function, fieldFormat, item.source);
      },
      sortable: true,
    });

    // Assume that if we are showing typical, there will be an actual too,
    // so we can add a column to describe how actual compares to typical.
    const nonTimeOfDayOrWeek = items.some(item => {
      const summaryRecFunc = item.source.function;
      return summaryRecFunc !== 'time_of_day' && summaryRecFunc !== 'time_of_week';
    });
    if (nonTimeOfDayOrWeek === true) {
      columns.push({
        field: 'metricDescriptionSort',
        name: i18n.translate('xpack.ml.anomaliesTable.metricDescriptionSortColumnName', {
          defaultMessage: 'description',
        }),
        render: (metricDescriptionSort, item) => (
          <DescriptionCell actual={item.actual} typical={item.typical} />
        ),
        textOnly: true,
        sortable: true,
      });
    }
  }

  if (jobIds && jobIds.length > 1) {
    columns.push({
      field: 'jobId',
      name: i18n.translate('xpack.ml.anomaliesTable.jobIdColumnName', {
        defaultMessage: 'job ID',
      }),
      sortable: true,
    });
  }

  const showExamples = items.some(item => item.entityName === 'mlcategory');
  if (showExamples === true) {
    columns.push({
      name: i18n.translate('xpack.ml.anomaliesTable.categoryExamplesColumnName', {
        defaultMessage: 'category examples',
      }),
      sortable: false,
      truncateText: true,
      render: item => {
        const examples = _.get(examplesByJobId, [item.jobId, item.entityValue], []);
        return (
          <EuiLink
            className="mlAnomalyCategoryExamples__link"
            onClick={() => toggleRow(item, ANOMALIES_TABLE_TABS.CATEGORY_EXAMPLES)}
          >
            {examples.map((example, i) => {
              return (
                <span key={`example${i}`} className="category-example">
                  {example}
                </span>
              );
            })}
          </EuiLink>
        );
      },
      textOnly: true,
      width: '13%',
    });
  }

  const showLinks = items.some(item => showLinksMenuForItem(item, showViewSeriesLink));

  if (showLinks === true) {
    columns.push({
      name: i18n.translate('xpack.ml.anomaliesTable.actionsColumnName', {
        defaultMessage: 'actions',
      }),
      render: item => {
        if (showLinksMenuForItem(item) === true) {
          return (
            <LinksMenu
              anomaly={item}
              showViewSeriesLink={showViewSeriesLink}
              isAggregatedData={isAggregatedData}
              interval={interval}
              timefilter={timefilter}
              showRuleEditorFlyout={showRuleEditorFlyout}
            />
          );
        } else {
          return null;
        }
      },
    });
  }

  return columns;
}
