import React, { useContext, useState, useMemo } from 'react';

import { Popover, List, ListSubheader, ListItemButton, ListItemText, ListItemIcon, Divider } from '@mui/material';
import parse from 'autosuggest-highlight/parse';
import match from 'autosuggest-highlight/match';

import { ChevronRight, ChevronLeft } from '@nebula.js/ui/icons';

import { useTheme } from '@nebula.js/ui/theme';

import useSessionModel from '@nebula.js/nucleus/src/hooks/useSessionModel';
import useLayout from '@nebula.js/nucleus/src/hooks/useLayout';
import useLibraryList from '../../hooks/useLibraryList';

import AppContext from '../../contexts/AppContext';

import Search from './Search';

function Field({ field, onSelect, sub, parts }) {
  return (
    <ListItemButton onClick={() => onSelect(field.qName)} data-key={field.qName}>
      <ListItemText>
        {parts.map((part, ix) => (
          <span
            // eslint-disable-next-line react/no-array-index-key
            key={ix}
            style={part.highlight ? { flex: '0 1 auto', backgroundColor: '#FFC72A' } : { flex: '0 1 auto' }}
          >
            {part.text}
          </span>
        ))}
      </ListItemText>
      {sub && <ChevronRight fontSize="small" />}
    </ListItemButton>
  );
}

function LibraryItem({ item, onSelect, parts }) {
  return (
    <ListItemButton onClick={() => onSelect(item.qInfo)} data-key={item.qInfo.qId}>
      <ListItemText>
        {parts.map((part, ix) => (
          <span
            // eslint-disable-next-line react/no-array-index-key
            key={ix}
            style={part.highlight ? { flex: '0 1 auto', backgroundColor: '#FFC72A' } : { flex: '0 1 auto' }}
          >
            {part.text}
          </span>
        ))}
      </ListItemText>
    </ListItemButton>
  );
}

function Aggr({ aggr, field, onSelect }) {
  return (
    <ListItemButton onClick={() => onSelect(aggr)} data-key={aggr}>
      <ListItemText>{`${aggr}(${field})`}</ListItemText>
    </ListItemButton>
  );
}

function LibraryList({ app, onSelect, title = '', type = 'dimension', searchTerm = '' }) {
  const [libraryItems] = useLibraryList(app, type);
  const sortedLibraryItems = useMemo(
    () => libraryItems.slice().sort((a, b) => a.qData.title.toLowerCase().localeCompare(b.qData.title.toLowerCase())),
    [libraryItems]
  );

  return libraryItems.length > 0 ? (
    <>
      <ListSubheader component="div" style={{ backgroundColor: 'inherit' }}>
        {title}
      </ListSubheader>
      {sortedLibraryItems.map((item) => {
        const matches = match(item.qData.title, searchTerm);
        const parts = parse(item.qData.title, matches);
        if (searchTerm && matches.length === 0) return null;
        return <LibraryItem key={item.qInfo.qId} item={item} onSelect={onSelect} parts={parts} />;
      })}
    </>
  ) : null;
}

export default function FieldsPopover({ alignTo, show, close, onSelected, type }) {
  const app = useContext(AppContext);
  const [selectedField, setSelectedField] = useState(null);
  const [searchTerm, setSearchTerm] = useState('');
  const theme = useTheme();
  const [model] = useSessionModel(
    {
      qInfo: {
        qType: 'FieldList',
        qId: 'FieldList',
      },
      qFieldListDef: {
        qShowDerivedFelds: false,
        qShowHidden: false,
        qShowSemantic: true,
        qShowSrcTables: true,
        qShowSystem: false,
      },
    },
    app
  );

  const [layout] = useLayout(model);

  const fields = useMemo(
    () =>
      (layout ? layout.qFieldList.qItems || [] : [])
        .slice()
        .sort((a, b) => a.qName.toLowerCase().localeCompare(b.qName.toLowerCase())),
    [layout]
  );

  const onSelect = (s) => {
    if (s && s.qId) {
      onSelected(s);
      close();
    } else if (type === 'measure') {
      setSelectedField(s);
    } else {
      onSelected({
        field: s,
      });
      close();
    }
  };

  const onAggregateSelected = (s) => {
    onSelected({
      field: selectedField,
      aggregation: s,
    });
    close();
  };

  return (
    <Popover
      open={show}
      onClose={close}
      anchorEl={alignTo.current}
      marginThreshold={16} // theme.spacing(1)
      elevation={3}
      anchorOrigin={{
        vertical: 'bottom',
        horizontal: 'center',
      }}
      transformOrigin={{
        vertical: 'top',
        horizontal: 'center',
      }}
      PaperProps={{
        style: { minWidth: '250px', maxHeight: '300px', background: theme.palette.background.lightest },
      }}
    >
      {!selectedField && <Search onChange={setSearchTerm} />}
      {selectedField && (
        <List dense component="nav">
          <ListItemButton onClick={() => setSelectedField(null)}>
            <ListItemIcon>
              <ChevronLeft />
            </ListItemIcon>
            <ListItemText>Back</ListItemText>
          </ListItemButton>
          <Divider />
          <ListSubheader component="div">Aggregation</ListSubheader>
          {['sum', 'count', 'avg', 'min', 'max'].map((v) => (
            <Aggr key={v} aggr={v} field={selectedField} onSelect={onAggregateSelected} />
          ))}
        </List>
      )}
      {!selectedField && fields.length > 0 && (
        <List dense component="nav" style={{ background: theme.palette.background.lightest }}>
          <LibraryList
            app={app}
            onSelect={onSelect}
            type={type}
            title={type === 'measure' ? 'Measures' : 'Dimensions'}
            searchTerm={searchTerm}
          />
          <ListSubheader component="div" style={{ backgroundColor: 'inherit' }}>
            Fields
          </ListSubheader>
          {fields.map((field) => {
            const matches = match(field.qName, searchTerm);
            const parts = parse(field.qName, matches);
            if (searchTerm && matches.length === 0) return null;
            return <Field key={field.qName} field={field} onSelect={onSelect} sub={type === 'measure'} parts={parts} />;
          })}
        </List>
      )}
    </Popover>
  );
}
