import * as _ from 'lodash';
import * as moment from 'moment-timezone';

import { code } from 'dashboard/generated/controlplane';
import twirp = code.justin.tv.eventbus.controlplane;

const SUCCESS_MSG = 'Success';

const SUCCESS_DISPLAY = 'Success';
const ERROR_DISPLAY = 'Error';

const RESOURCE_DISPLAYS: { [key: string]: string } = {
  SERVICE: 'Service',
  ACCOUNT: 'Account',
  SUBSCRIPTION: 'Subscription',
  ['IAM ROLE']: 'IAM Role',
  ['SUBSCRIPTION TARGET']: 'Subscription Target',
};

export type Column = 'timestamp' | 'userName' | 'resourceType' | 'resourceName' | 'action' | 'result' | 'description';
export type filter = [Column, string];

export const COLUMN_NAMES: { [key in Column]: string } = {
  timestamp: 'Timestamp',
  userName: 'User',
  resourceType: 'Resource Type',
  resourceName: 'Resource Name',
  action: 'Action',
  result: 'Result',
  description: 'Description',
};

const ACTION_DISPLAYS: { [key: string]: string } = {
  CREATE: 'Create',
  UPDATE: 'Update',
  DELETE: 'Delete',
};

export const displayFunctions: { [key in Column]: (auditLog: twirp.AuditLog) => string } = {
  description: (auditLog: twirp.AuditLog) => auditLog.result === SUCCESS_MSG ? '' : auditLog.result,
  result: (auditLog: twirp.AuditLog) => auditLog.result === SUCCESS_MSG ? SUCCESS_DISPLAY : ERROR_DISPLAY,
  timestamp: (auditLog: twirp.AuditLog) => moment.unix(_.get(auditLog, 'timestamp.seconds', 0)).tz('UTC').format('MM/DD/YYYY HH:mm:ss z'),
  resourceType: (auditLog: twirp.AuditLog) => RESOURCE_DISPLAYS[auditLog.resourceType] || 'Unknown',
  userName: (auditLog: twirp.AuditLog) => auditLog.userName,
  resourceName: (auditLog: twirp.AuditLog) => auditLog.resourceName,
  action: (auditLog: twirp.AuditLog) => ACTION_DISPLAYS[auditLog.action] || 'Unknown',
};

export const filterableFields: Column[] = ['userName', 'resourceType', 'action', 'result'];

// Filtering logic is tricky: Any specific value in a column is acceptable if it matches *any* of the filters. Yet we display rows only if they match filters for all columns.
export function filterAuditLogs(auditLogs: twirp.AuditLog[], filters: filter[], fields: Column[]) {
  return _.filter(auditLogs, (auditLog) => {
    for (const field of fields) {
      let columnIsValid = false;

      const filtersForField = _.filter(filters, (f: filter) => {
        return f[0] === field;
      });

      // If there's no filters for this field, then column is valid
      if (_.isEmpty(filtersForField)) {
        columnIsValid = true;
      }

      // Iterate over the filters for this field. If any match, column is valid.
      for (const f of filtersForField) {
        const [key, value]: filter = f;
        if (displayFunctions[key](auditLog) === value) {
          columnIsValid = true;
        }
      }

      // If any columns for the row are invalid, the entire row is invalid
      if (!columnIsValid) {
        return false;
      }
    }

    return true;
  });
}
