// 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 {globals} from '../globals';
import {DESELECT, SELECT_ALL} from '../icons';
import {Button} from './button';
import {Checkbox} from './checkbox';
import {EmptyState} from './empty_state';
import {Popup, PopupPosition} from './popup';
import {TextInput} from './text_input';

export interface Option {
  // The ID is used to indentify this option, and is used in callbacks.
  id: string;
  // This is the name displayed and used for searching.
  name: string;
  // Whether the option is selected or not.
  checked: boolean;
}

export interface MultiSelectDiff {
  id: string;
  checked: boolean;
}

export interface MultiSelectAttrs {
  icon?: string;
  label: string;
  options: Option[];
  onChange?: (diffs: MultiSelectDiff[]) => void;
  repeatCheckedItemsAtTop?: boolean;
  showNumSelected?: boolean;
  popupPosition?: PopupPosition;
}

// A component which shows a list of items with checkboxes, allowing the user to
// select from the list which ones they want to be selected.
// Also provides search functionality.
// This component is entirely controlled and callbacks must be supplied for when
// the selected items changes, and when the search term changes.
// There is an optional boolean flag to enable repeating the selected items at
// the top of the list for easy access - defaults to false.
export class MultiSelect implements m.ClassComponent<MultiSelectAttrs> {
  private searchText: string = '';
  view({attrs}: m.CVnode<MultiSelectAttrs>) {
    const {
      icon,
      popupPosition = PopupPosition.Auto,
    } = attrs;

    return m(
        Popup,
        {
          trigger: m(Button, {label: this.labelText(attrs), icon}),
          position: popupPosition,
        },
        this.renderPopup(attrs),
    );
  }

  private labelText(attrs: MultiSelectAttrs): string {
    const {
      options,
      showNumSelected,
      label,
    } = attrs;

    if (showNumSelected) {
      const numSelected = options.filter(({checked}) => checked).length;
      return `${label} (${numSelected} selected)`;
    } else {
      return label;
    }
  }

  private renderPopup(attrs: MultiSelectAttrs) {
    const {
      options,
    } = attrs;

    const filteredItems = options.filter(({name}) => {
      return name.toLowerCase().includes(this.searchText.toLowerCase());
    });

    return m(
        '.pf-multiselect-popup',
        this.renderSearchBox(),
        this.renderListOfItems(attrs, filteredItems),
    );
  }

  private renderListOfItems(attrs: MultiSelectAttrs, options: Option[]) {
    const {
      repeatCheckedItemsAtTop,
      onChange = () => {},
    } = attrs;
    const allChecked = options.every(({checked}) => checked);
    const anyChecked = options.some(({checked}) => checked);

    if (options.length === 0) {
      return m(EmptyState, {
        header: `No results for '${this.searchText}'`,
      });
    } else {
      return [m(
          '.pf-list',
          repeatCheckedItemsAtTop && anyChecked &&
              m(
                  '.pf-multiselect-container',
                  m(
                      '.pf-multiselect-header',
                      m('span',
                        this.searchText === '' ? 'Selected' :
                                                 `Selected (Filtered)`),
                      m(Button, {
                        label: this.searchText === '' ? 'Clear All' :
                                                        'Clear Filtered',
                        icon: DESELECT,
                        minimal: true,
                        onclick: () => {
                          const diffs =
                              options.filter(({checked}) => checked)
                                  .map(({id}) => ({id, checked: false}));
                          onChange(diffs);
                          globals.rafScheduler.scheduleFullRedraw();
                        },
                        disabled: !anyChecked,
                      }),
                      ),
                  this.renderOptions(
                      attrs, options.filter(({checked}) => checked)),
                  ),
          m(
              '.pf-multiselect-container',
              m(
                  '.pf-multiselect-header',
                  m('span',
                    this.searchText === '' ? 'Options' : `Options (Filtered)`),
                  m(Button, {
                    label: this.searchText === '' ? 'Select All' :
                                                    'Select Filtered',
                    icon: SELECT_ALL,
                    minimal: true,
                    compact: true,
                    onclick: () => {
                      const diffs = options.filter(({checked}) => !checked)
                                        .map(({id}) => ({id, checked: true}));
                      onChange(diffs);
                      globals.rafScheduler.scheduleFullRedraw();
                    },
                    disabled: allChecked,
                  }),
                  m(Button, {
                    label: this.searchText === '' ? 'Clear All' :
                                                    'Clear Filtered',
                    icon: DESELECT,
                    minimal: true,
                    compact: true,
                    onclick: () => {
                      const diffs = options.filter(({checked}) => checked)
                                        .map(({id}) => ({id, checked: false}));
                      onChange(diffs);
                      globals.rafScheduler.scheduleFullRedraw();
                    },
                    disabled: !anyChecked,
                  }),
                  ),
              this.renderOptions(attrs, options),
              ),
          )];
    }
  }

  private renderSearchBox() {
    return m(
        '.pf-search-bar',
        m(TextInput, {
          oninput: (event: Event) => {
            const eventTarget = event.target as HTMLTextAreaElement;
            this.searchText = eventTarget.value;
            globals.rafScheduler.scheduleFullRedraw();
          },
          value: this.searchText,
          placeholder: 'Filter options...',
          extraClasses: 'pf-search-box',
        }),
        this.renderClearButton(),
    );
  }

  private renderClearButton() {
    if (this.searchText != '') {
      return m(Button, {
        onclick: () => {
          this.searchText = '';
          globals.rafScheduler.scheduleFullRedraw();
        },
        label: '',
        icon: 'close',
        minimal: true,
      });
    } else {
      return null;
    }
  }

  private renderOptions(attrs: MultiSelectAttrs, options: Option[]) {
    const {
      onChange = () => {},
    } = attrs;

    return options.map((item) => {
      const {checked, name, id} = item;
      return m(Checkbox, {
        label: name,
        key: id,  // Prevents transitions jumping between items when searching
        checked,
        classes: 'pf-multiselect-item',
        onchange: () => {
          onChange([{id, checked: !checked}]);
          globals.rafScheduler.scheduleFullRedraw();
        },
      });
    });
  }
}
