// Copyright (C) 2023 The Android Open Source Project
//
// Licensed 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 m from 'mithril';

import {exists} from '../base/utils';

import {HTMLInputAttrs} from './common';
import {Menu, MenuItem} from './menu';
import {scheduleFullRedraw} from './raf';
import {TextInput} from './text_input';


export class Select implements m.ClassComponent<HTMLInputAttrs> {
  view({attrs, children}: m.CVnode<HTMLInputAttrs>) {
    return m('select.pf-select', attrs, children);
  }
}

export interface FilterableSelectAttrs {
  // Whether to show a search box. Defaults to false.
  filterable?: boolean;
  // The values to show in the select.
  values: string[];
  // Called when the user selects an option.
  onSelected: (value: string) => void;
  // If set, only the first maxDisplayedItems will be shown.
  maxDisplayedItems?: number;
  // Whether the input field should be focused when the widget is created.
  autofocusInput?: boolean;
}

// A select widget with a search box, allowing the user to filter the options.
export class FilterableSelect implements
    m.ClassComponent<FilterableSelectAttrs> {
  searchText = '';

  view({attrs}: m.CVnode<FilterableSelectAttrs>) {
    const filteredValues = attrs.values.filter((name) => {
      return name.toLowerCase().includes(this.searchText.toLowerCase());
    });

    const displayedValues = attrs.maxDisplayedItems === undefined ?
        filteredValues :
        filteredValues.slice(0, attrs.maxDisplayedItems);

    const extraItems = exists(attrs.maxDisplayedItems) &&
        Math.max(0, filteredValues.length - attrs.maxDisplayedItems);

    // TODO(altimin): when the user presses enter and there is only one item,
    // select the first one.
    // MAYBE(altimin): when the user presses enter and there are multiple items,
    // select the first one.
    return m(
        'div',
        m('.pf-search-bar',
          m(TextInput, {
            oninput: (event: Event) => {
              const eventTarget = event.target as HTMLTextAreaElement;
              this.searchText = eventTarget.value;
              scheduleFullRedraw();
            },
            onload: (event: Event) => {
              if (!attrs.autofocusInput) return;
              const eventTarget = event.target as HTMLTextAreaElement;
              eventTarget.focus();
            },
            value: this.searchText,
            placeholder: 'Filter...',
            className: 'pf-search-box',
          }),
          m(Menu,
            ...displayedValues.map((value) => m(MenuItem, {
                                     label: value,
                                     onclick: () => attrs.onSelected(value),
                                   })),
            Boolean(extraItems) && m('i', `+${extraItems} more`))));
  }
}
