
// import react
import clsx from 'clsx';
import { Virtuoso } from 'react-virtuoso';
import ResizeObserver from 'resize-observer-polyfill';
import React, { useRef, useEffect, useState, useMemo } from 'react';

// locals
import Item from './Item';
import Confirm from '../../../Confirm';
import ApiSignal from '../../../../signals/Api';
import { useSignal } from '../../../../signal';
import { useFrames } from '../../../../data/useFrame';
import { current as TeamSignal } from '../../../../signals/Teams';

// debounce load next
let timeout = null;
const debounceLoadNext = (loadNext, time = 500) => {
  // if timeout, return
  if (timeout) return;

  // create timeout
  timeout = setTimeout(() => {
    // clear timeout
    clearTimeout(timeout);

    // load next
    timeout = null;

    // load next
    loadNext();
  }, time);
};

/**
 * component chirps
 *
 * @param props 
 */
const ComponentWorkflowChatList = (props = {}) => {
  // refs
  const virtuoso = useRef(null);

  // signals
  const [sApi] = useSignal(ApiSignal);
  const [team] = useSignal(TeamSignal);

  // state
  const [remove, setRemove] = useState(null);
  const [scrolled, setScrolled] = useState(false);
  const [workflow, setWorkflow] = useState(typeof props.workflow === 'object' ? props.workflow : null);
  const [removing, setRemoving] = useState(false);
  
  // items
  const {
    total,
    frames,
    loadMore,
    handleItem,
    handleRemove,
  } = useFrames({
    full     : true,
    team     : team?.id,
    search   : props.search,
    subject  : props.subject,
    workflow : workflow?.id,
  }, {
    disable : !workflow?.id || (!team?.id && !sApi.options?.query?.token),
    
    sort : (a, b) => {
      return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
    },
    filter : (frame) => {
      // return subject/workflow
      return (frame.workflow === workflow?.id) && (frame.subject === props.subject);
    },
  });
  
  /**
   * on delete
   *
   * @param message 
   */
  const onDelete = async (message) => {
    // check removing
    if (removing) return;
    
    // loading delete
    setRemoving(true);

    // try/catch
    try {
      // delete message
      await sApi.Workflow.Frame.delete(workflow, message);

      // remove from items
      handleRemove(message);
    } catch (e) {
      console.log(e);
    } finally {
      setRemove(null);
      setRemoving(false);
    }
  };

  // use effect
  useEffect(() => {
    // check typeof
    if (typeof props.workflow !== 'string') return;
    
    // load workflow
    sApi.Workflow.get(props.workflow).then((gotWorkflow) => {
      // set workflow
      setWorkflow(gotWorkflow);
    });
  }, [props.workflow]);
  useEffect(() => {
    // add listener
    handleItem(props.output);
  }, [JSON.stringify(props.output)]);
  useEffect(() => {
    // scroll element
    const scrollElement = document.body;

    // scroll timeout
    let scrollTimeout;
    
    // on window scroll up, set scrolled to true
    const onScroll = (e) => {
      // clear timeout
      clearTimeout(scrollTimeout);
      
      // check scrolled above bottom of window within 500
      if (window.scrollY < (scrollElement.scrollHeight - window.innerHeight - 500)) {
        // set true
        setScrolled(true);
      } else {
        // set false
        setScrolled(false);
      }
    };

    // on resize
    const onResize = () => {
      // scroll to bottom
      if (scrolled) return;

      // timeout
      clearTimeout(scrollTimeout);
      
      // scroll to bottom
      virtuoso.current?.scrollToIndex(999999);
    };

    // on scroll
    window.addEventListener('scroll', onScroll);
    
    // create resize observer on window body
    const resizeObserver = new ResizeObserver(onResize);

    // observe body
    resizeObserver.observe(scrollElement);

    // return
    return () => {
      // clear timeout
      clearTimeout(scrollTimeout);

      // remove listener
      window.removeEventListener('scroll', onScroll);

      // remove resize observer
      resizeObserver.unobserve(scrollElement);

      // disconnect
      resizeObserver.disconnect();
    };
  }, [workflow?.id, props.selected?.id, virtuoso.current]);

  // reversed frames
  const reversedFrames = useMemo(() => {
    return [...frames].reverse();
  }, [frames]);

  // return jsx
  return (
    <>
      <div className={clsx(
        'relative flex-1 w-full min-w-0 h-full studio',
      )}>
        {!!frames?.length && (
          <Virtuoso
            useWindowScroll={!props.noWindowScroll}

            ref={virtuoso} 
            data={reversedFrames}
            overscan={2000}
            totalCount={total}
            followOutput="auto"
            startReached={() => debounceLoadNext(loadMore)}
            computeItemKey={(index, item) => item.id}
            increaseViewportBy={2000}
            initialTopMostItemIndex={9999999}

            itemContent={(index, item) => {

              // return content
              return (
                <Item
                  item={item}
                  isLast={index === (total - 1)}
                  isFirst={index === 0}
                  onRetry={props.onRetry}
                  onFrame={props.onFrame}
                  selected={props.selected}
                  workflow={workflow}
                  onSelect={props.onSelect}
                  removing={removing && (remove?.id === item?.id)}
                  onDelete={() => setRemove(item)}
                />
              );
            }}
          />
        )}
      </div>

      <Confirm
        open={!!remove}
        title={sApi.translate('workflow:dialog.message.remove.title', 'Remove Workflow', remove)}
        submit={sApi.translate('workflow:button.confirm', 'Confirm')}
        onClose={() => setRemove(null)}
        subtitle={sApi.translate('workflow:dialog.message.remove.message', 'Are you sure you want to remove this workflow?', remove)}
        onConfirm={() => onDelete(remove)}
      />
    </>
  );
};

// export default
export default ComponentWorkflowChatList;