import { useEffect, useRef, useState } from 'react'
import ProcessItem from "./ProcessItem"
import styles from './styles.module.css'

interface Task {
  (): Promise<void>
}

type ProcessItem = {
  task: Task
  label: string
}

type ProcessFlowProps = {
  items: ProcessItem[]
  onDone: () => void
}

enum ProcessStatus {
  Idle,
  Pending,
  Done,
}

const createChaining = (tasks: Task[], callback: (idx: number) => void) => {
  return tasks.reduce((chain, task, idx) => {
    return chain.then(task).then(()=> callback(idx))
  }, Promise.resolve())
}

const getMultiplier = (currentIdx: number, length: number): number => {
  return Math.max(length - (currentIdx + 1) - 1, 0)
}

const calculateTop = (currentIdx: number, length: number, items: HTMLDivElement[]): number => {

  return items.slice(currentIdx + 2).reduce((accumulator, item) => {
    if (!item) return accumulator;
    return accumulator + item.clientHeight
  }, 1) + 8 * getMultiplier(currentIdx, length)
}

function ProcessFlow({ items, onDone }: ProcessFlowProps): JSX.Element {
  const [status, setStatus] = useState(ProcessStatus.Idle)
  const [doneTaskIdx, setDoneTaskIdx] = useState(-1)
  const itemsRef = useRef([] as HTMLDivElement[]);
  const tasks = items.map(({ task }) => task)
  const [rerender, setRerender] = useState(false);
  rerender

  useEffect(() => {
    setRerender((prev) => !prev);
  }, [itemsRef])

  useEffect(() => {
    if (status !== ProcessStatus.Idle) return
    setStatus(ProcessStatus.Pending)
    createChaining(tasks, setDoneTaskIdx)
      .then(() => setStatus(ProcessStatus.Done))
      .then(() => onDone())
  }, [status, tasks, onDone])

  const toItems = ({ label }: ProcessItem, idx: number): JSX.Element => {
    return <ProcessItem
      key={idx}
      label={label}
      top={calculateTop(doneTaskIdx, items.length, itemsRef.current)}
      isDone={idx <= doneTaskIdx}
      refItem={(el) => (itemsRef.current[idx] = el as HTMLDivElement)}
    />
  }
  return (
    <div className={`${styles['process-items']} mt-24`}>
      {items.map(toItems)}
    </div>
  )
}

export default ProcessFlow
