/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 *
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

/*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import React, {
  FunctionComponent,
  HTMLAttributes,
  ButtonHTMLAttributes,
  MouseEventHandler,
} from 'react';
import { CommonProps, ExclusiveUnion, keysOf } from '../common';
import classNames from 'classnames';
import { OuiIcon, IconType } from '../icon';

interface Type {
  iconType: IconType;
  color: string | keyof typeof colorToClassNameMap;
}

interface OuiSuggestItemPropsBase {
  /**
   * Takes 'iconType' for OuiIcon and 'color'. 'color' can be tint1 through tint9.
   */
  type: Type;

  /**
   * Label or primary text.
   */
  label: string;

  /**
   * Description or secondary text (optional).
   */
  description?: string;

  /**
   * Label display is 'fixed' by default. Label will increase its width beyond 50% if needed with 'expand'.
   */
  labelDisplay?: keyof typeof labelDisplayToClassMap;

  /**
   * Width of 'label' when 'labelDisplay' is set to 'fixed'.
   * Accepts multiples of 10, from 20 to 90. Defaults to 50.
   */
  labelWidth?: LabelWidthSize;

  /**
   * Set the way in which 'description' is displayed, defaults to 'truncate'.
   */
  descriptionDisplay?: keyof typeof descriptionDisplayToClassMap;
}

type PropsForDiv = Omit<HTMLAttributes<HTMLDivElement>, 'onClick'>;
type PropsForButton = Omit<
  ButtonHTMLAttributes<HTMLButtonElement>,
  'onClick' | 'type'
> & {
  onClick: MouseEventHandler<HTMLButtonElement> | undefined;
};

export type OuiSuggestItemProps = CommonProps &
  OuiSuggestItemPropsBase &
  ExclusiveUnion<PropsForDiv, PropsForButton>;

interface ColorToClassMap {
  tint0: string;
  tint1: string;
  tint2: string;
  tint3: string;
  tint4: string;
  tint5: string;
  tint6: string;
  tint7: string;
  tint8: string;
  tint9: string;
  tint10: string;
  [key: string]: string;
}

type LabelWidthSize = '20' | '30' | '40' | '50' | '60' | '70' | '80' | '90';

const colorToClassNameMap: ColorToClassMap = {
  tint0: 'ouiSuggestItem__type--tint0',
  tint1: 'ouiSuggestItem__type--tint1',
  tint2: 'ouiSuggestItem__type--tint2',
  tint3: 'ouiSuggestItem__type--tint3',
  tint4: 'ouiSuggestItem__type--tint4',
  tint5: 'ouiSuggestItem__type--tint5',
  tint6: 'ouiSuggestItem__type--tint6',
  tint7: 'ouiSuggestItem__type--tint7',
  tint8: 'ouiSuggestItem__type--tint8',
  tint9: 'ouiSuggestItem__type--tint9',
  tint10: 'ouiSuggestItem__type--tint10',
};

export const COLORS = keysOf(colorToClassNameMap);

const labelDisplayToClassMap = {
  fixed: 'ouiSuggestItem__labelDisplay--fixed',
  expand: 'ouiSuggestItem__labelDisplay--expand',
};

const descriptionDisplayToClassMap = {
  truncate: 'ouiSuggestItem__description--truncate',
  wrap: 'ouiSuggestItem__description--wrap',
};

export const DISPLAYS = keysOf(labelDisplayToClassMap);

export const OuiSuggestItem: FunctionComponent<OuiSuggestItemProps> = ({
  className,
  label,
  type,
  labelDisplay = 'fixed',
  labelWidth = '50',
  description,
  descriptionDisplay = 'truncate',
  onClick,
  ...rest
}) => {
  const classes = classNames(
    'ouiSuggestItem',
    {
      'ouiSuggestItem-isClickable': onClick,
    },
    className
  );

  let colorClass = '';

  const labelDisplayCalculated = !description ? 'expand' : labelDisplay;

  const labelClassNames = classNames(
    'ouiSuggestItem__label',
    labelDisplayToClassMap[labelDisplayCalculated],
    {
      [`ouiSuggestItem__label--width${labelWidth}`]: labelDisplay === 'fixed',
    }
  );

  const descriptionClassNames = classNames(
    'ouiSuggestItem__description',
    descriptionDisplayToClassMap[descriptionDisplay]
  );

  if (type && type.color) {
    if (COLORS.indexOf(type.color as string) > -1) {
      colorClass = colorToClassNameMap[type.color];
    }
  }

  const innerContent = (
    <React.Fragment>
      <span className={`ouiSuggestItem__type ${colorClass}`}>
        <OuiIcon
          type={type.iconType}
          color="inherit" // forces the icon to inherit its parent color
        />
      </span>
      <span className={labelClassNames}>{label}</span>
      {description && (
        <span className={descriptionClassNames}>{description}</span>
      )}
    </React.Fragment>
  );

  if (onClick) {
    return (
      <button
        onClick={onClick}
        className={classes}
        {...(rest as PropsForButton)}>
        {innerContent}
      </button>
    );
  } else {
    return (
      <div className={classes} {...(rest as PropsForDiv)}>
        {innerContent}
      </div>
    );
  }
};