import React from 'react';

import {LoadReturn} from '@workday/canvas-kit-react/collection';
import {
  Combobox,
  useComboboxInput,
  useComboboxInputArbitrary,
  useComboboxLoader,
  useComboboxModel,
} from '@workday/canvas-kit-react/combobox';
import {
  composeHooks,
  createElemPropsHook,
  createSubcomponent,
} from '@workday/canvas-kit-react/common';
import {FormField} from '@workday/canvas-kit-react/form-field';
import {LoadingDots} from '@workday/canvas-kit-react/loading-dots';
import {StyledMenuItem} from '@workday/canvas-kit-react/menu';
import {InputGroup, TextInput} from '@workday/canvas-kit-react/text-input';
import {createStencil, px2rem} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

const colors = ['Red', 'Blue', 'Purple', 'Green', 'Pink'];
const fruits = ['Apple', 'Orange', 'Banana', 'Grape', 'Lemon', 'Lime'];
const options = Array(1000)
  .fill('')
  .map((_, index) => {
    return `${colors[index % colors.length]} ${fruits[index % fruits.length]} ${index + 1}`;
  });

const simulatedDelay = (window as any).Cypress ? 5 : 300;

const useAutocompleteInput = composeHooks(
  createElemPropsHook(useComboboxModel)(model => {
    return {
      onKeyPress(event: React.KeyboardEvent) {
        model.events.show(event);
      },
    };
  }),
  useComboboxInputArbitrary,
  useComboboxInput
);

const loadingDotsStencil = createStencil({
  base: {
    transition: 'opacity 100ms ease',
    '& [data-part="loading-dots"]': {
      display: 'flex',
      transform: 'scale(0.3)',
    },
  },
  modifiers: {
    isLoading: {
      true: {
        opacity: system.opacity.full,
      },
      false: {
        opacity: system.opacity.zero,
      },
    },
  },
});

const AutoCompleteInput = createSubcomponent(TextInput)({
  modelHook: useComboboxModel,
  elemPropsHook: useAutocompleteInput,
})<{isLoading?: boolean}>(({isLoading, ...elemProps}, Element) => {
  return (
    <InputGroup>
      <InputGroup.Input as={Element} {...elemProps} />
      <InputGroup.InnerEnd
        cs={loadingDotsStencil({isLoading})}
        width={px2rem(20)}
        data-loading={isLoading}
      >
        <LoadingDots data-part="loading-dots" />
      </InputGroup.InnerEnd>
      <InputGroup.InnerEnd>
        <InputGroup.ClearButton data-testid="clear" />
      </InputGroup.InnerEnd>
    </InputGroup>
  );
});

export default () => {
  const {model, loader} = useComboboxLoader(
    {
      // You can start with any number that makes sense.
      total: 0,

      // Pick whatever number makes sense for your API
      pageSize: 20,

      // A load function that will be called by the loader. You must return a promise that returns
      // an object like `{items: [], total: 0}`. The `items` will be merged into the loader's cache
      async load({pageNumber, pageSize, filter}) {
        return new Promise<LoadReturn<string>>(resolve => {
          // simulate a server response by resolving after a period of time
          setTimeout(() => {
            // simulate paging and filtering based on pre-computed items
            const start = (pageNumber - 1) * pageSize;
            const end = start + pageSize;
            const filteredItems = options.filter(item => {
              if (filter === '' || typeof filter !== 'string') {
                return true;
              }
              return item.toLowerCase().includes(filter.toLowerCase());
            });

            const total = filteredItems.length;
            const items = filteredItems.slice(start, end);

            resolve({
              items,
              total,
            });
          }, simulatedDelay);
        });
      },
      onShow() {
        // The `shouldLoad` cancels while the combobox menu is hidden, so let's load when it is
        // visible
        loader.load();
      },
    },
    useComboboxModel
  );

  return (
    <FormField orientation="horizontalStart" isRequired>
      <FormField.Label>Fruit</FormField.Label>
      <FormField.Field>
        <Combobox model={model} onChange={event => console.log('input', event.currentTarget.value)}>
          <FormField.Input as={AutoCompleteInput} isLoading={loader.isLoading} />
          <Combobox.Menu.Popper>
            <Combobox.Menu.Card>
              {model.state.items.length < 1 ? (
                <StyledMenuItem as="span">No Results Found</StyledMenuItem>
              ) : (
                <Combobox.Menu.List cs={{maxHeight: px2rem(200)}}>
                  {item => <Combobox.Menu.Item>{item}</Combobox.Menu.Item>}
                </Combobox.Menu.List>
              )}
            </Combobox.Menu.Card>
          </Combobox.Menu.Popper>
        </Combobox>
      </FormField.Field>
    </FormField>
  );
};
