import { Index } from 'flexsearch';
import { useState } from 'react';
import DebouncedInput from './DebouncedInput';
import { useForm } from 'react-hook-form';

export function Catalog({
  datasets,
  facets,
}: {
  datasets: any[];
  facets: string[];
}) {
  const [indexFilter, setIndexFilter] = useState('');
  const index = new Index({ tokenize: 'full' });
  datasets.forEach((dataset) =>
    index.add(
      dataset._id,
      //This will join every metadata value + the url_path into one big string and index that
      Object.entries(dataset.metadata).reduce(
        (acc, curr) => acc + ' ' + curr[1].toString(),
        ''
      ) +
        ' ' +
        dataset.url_path
    )
  );

  const facetValues = facets
    ? facets.reduce((acc, facet) => {
        const possibleValues = datasets.reduce((acc, curr) => {
          const facetValue = curr.metadata[facet];
          if (facetValue) {
            return Array.isArray(facetValue)
              ? acc.concat(facetValue)
              : acc.concat([facetValue]);
          }
          return acc;
        }, []);
        acc[facet] = {
          possibleValues: [...new Set(possibleValues)],
          selectedValue: null,
        };
        return acc;
      }, {})
    : [];

  const { register, watch } = useForm(facetValues);

  const filteredDatasets = datasets
    // First filter by flex search
    .filter((dataset) =>
      indexFilter !== ''
        ? index.search(indexFilter).includes(dataset._id)
        : true
    )
    //Then check if the selectedValue for the given facet is included in the dataset metadata
    .filter((dataset) => {
      //Avoids a server rendering breakage
      if (!watch() || Object.keys(watch()).length === 0) return true
      //This will filter only the key pairs of the metadata values that were selected as facets
      const datasetFacets = Object.entries(dataset.metadata).filter((entry) =>
        facets.includes(entry[0])
      );
      //Check if the value present is included in the selected value in the form
      return datasetFacets.every((elem) =>
        watch()[elem[0]].selectedValue
          ? (elem[1] as string | string[]).includes(
              watch()[elem[0]].selectedValue
            )
          : true
      );
    });

  return (
    <>
      <DebouncedInput
        value={indexFilter ?? ''}
        onChange={(value) => setIndexFilter(String(value))}
        className="p-2 text-sm shadow border border-block mr-1"
        placeholder="Search all datasets..."
      />
      {Object.entries(facetValues).map((elem) => (
        <select
          key={elem[0]}
          defaultValue=""
          className="p-2 ml-1 text-sm shadow border border-block"
          {...register(elem[0] + '.selectedValue')}
        >
          <option value="">
            Filter by {elem[0]}
          </option>
          {(elem[1] as { possibleValues: string[] }).possibleValues.map(
            (val) => (
              <option
                key={val}
                className="dark:bg-white dark:text-black"
                value={val}
              >
                {val}
              </option>
            )
          )}
        </select>
      ))}
      <ul className='mb-5 pl-6 mt-5 list-disc'>
        {filteredDatasets.map((dataset) => (
          <li className='py-2' key={dataset._id}>
            <a className='font-medium underline' href={dataset.url_path}>
              {dataset.metadata.title
                ? dataset.metadata.title
                : dataset.url_path}
            </a>
          </li>
        ))}
      </ul>
    </>
  );
}

