import {
  Match,
  Show,
  createEffect,
  createMemo,
  createSignal,
  mergeProps,
} from "solid-js";

function List(props) {
  props = mergeProps({ items: [], showHeader: true, selectable: true }, props);
  const [listItems, setListItems] = createSignal([]);
  const selectedItems = createMemo(() =>
    listItems()
      .filter((item) => item.selected())
      .map((item) => item.item)
  );
  const allItemsSelected = createMemo(() =>
    listItems().every((item) => item.selected())
  );
  createEffect(() => {
    setListItems(
      props.items.map((item) => {
        const [selected, setSelected] = createSignal(false);
        return {
          selected,
          setSelected,
          item: item,
        };
      })
    );
  });
  createEffect(() => {
    if (!props.onListItemsSelect) return;
    props.onListItemsSelect(selectedItems());
  });

  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        if (props.onLazyLoad) {
          props.onLazyLoad();
        }
      }
    });
  });

  const [lazyLoadTriggerElement, setLazyLoadTriggerElement] = createSignal();
  createEffect(() => {
    observer.observe(lazyLoadTriggerElement());
  });

  const [scrollTop, setScrollTop] = createSignal(0);
  const itemsMutationObserver = new MutationObserver(() => {
    itemsContainerElement().scrollTop = scrollTop();
  });
  const [itemsContainerElement, setItemsContainerElement] = createSignal();
  createEffect(() => {
    if (!itemsContainerElement()) return;
    itemsMutationObserver.observe(itemsContainerElement(), { childList: true });
  });

  function handleListItemClick(item) {
    if (!props.onListItemClick) return;
    props.onListItemClick(item);
  }

  function handleToggleAllItems() {
    if (allItemsSelected()) {
      listItems().forEach((item) => item.setSelected(false));
      return;
    }
    listItems().forEach((item) => item.setSelected(true));
  }

  function renderHeaderRow(columns) {
    columns = columns.filter((column) => !column.hidden);
    if (!props.showHeader) return null;
    return (
      <div class="list-group-item d-flex p-0">
        <div class="d-flex flex-fill border-bottom border-2 fw-bold overflow-y-scroll">
          <Show when={props.selectable}>
            <div
              class="d-flex align-items-center justify-content-center border-end py-2 px-3"
              onClick={() => handleToggleAllItems()}
            >
              <input
                class="form-check-input m-0"
                type="checkbox"
                checked={allItemsSelected()}
                id={""}
              />
            </div>
          </Show>
          <For each={columns}>
            {(column) => (
              <div
                class={"d-flex p-2" + (column.width ? "" : " flex-fill")}
                style={column.width ? `width:${column.width}em` : ""}
              >
                <Show when={column.withIcons}>
                  <div class="pe-2" style="color: transparent">
                    <i class="bi-folder2" />
                  </div>
                </Show>
                <div class="text-truncate">
                  <span>{column.name}</span>
                </div>
              </div>
            )}
          </For>
        </div>
      </div>
    );
  }

  function renderListItem(listItem, columns) {
    columns = columns.filter((column) => !column.hidden);
    let item = listItem.item;
    return (
      <a
        role="button"
        class="list-group-item list-group-item-action d-flex p-0 overflow-x-hidden border-0 border-bottom border-1"
        style="max-width: 100%"
      >
        <Show when={props.selectable}>
          <div
            class="d-flex align-items-center justify-content-center border-end py-2 px-3"
            onClick={() => listItem.setSelected(!listItem.selected())}
          >
            <input
              class="form-check-input m-0"
              type="checkbox"
              checked={listItem.selected()}
              id={""}
            />
          </div>
        </Show>
        <div
          class="d-flex flex-fill overflow-hidden"
          onClick={() => handleListItemClick(item)}
        >
          <For each={columns}>
            {(column) => (
              <div
                class={
                  "d-flex p-2 align-items-center" +
                  (column.width ? " flex-shrink-0" : " flex-fill")
                }
                style={
                  "overflow: hidden; " +
                  (column.width ? `width:${column.width}em` : "")
                }
              >
                <Show when={column.withIcons}>
                  <Show when={!item[column.id].icon}>
                    <div class="pe-2" style="color: transparent">
                      <i class="bi-folder2" />
                    </div>
                  </Show>
                  <Show when={item[column.id].icon}>
                    <div class="pe-2">
                      <i class={item[column.id].icon} />
                    </div>
                  </Show>
                </Show>
                <Switch>
                  <Match when={item[column.id].html}>
                    {item[column.id].html}
                  </Match>
                  <Match when={item[column.id].text}>
                    <div class="text-truncate">
                      <span>{item[column.id]?.text}</span>
                    </div>
                  </Match>
                </Switch>
              </div>
            )}
          </For>
        </div>
      </a>
    );
  }

  return (
    <div
      style={props.style}
      class={
        "list-group d-flex flex-column overflow-hidden " + (props.class || "")
      }
    >
      {renderHeaderRow(props.columns)}
      <div
        class="list-group-item p-0 flex-fill overflow-y-scroll"
        style="min-width: 0"
        onScroll={(event) => setScrollTop(event.target.scrollTop)}
        ref={setItemsContainerElement}
      >
        <For each={listItems()}>
          {(listItem) => renderListItem(listItem, props.columns)}
        </For>
        <div
          style="width: 100%; height: 3em;"
          ref={setLazyLoadTriggerElement}
        ></div>
      </div>
    </div>
  );
}

export default List;
