import {FC, memo, useCallback, useEffect, useMemo, useState} from "react";
import {FactorySelect} from "../FactorySelect/FactorySelect";
import {useFactories} from "../../../src/hooks/useFactories";
import {EnrichedEntity, Entity, Group} from "../../../src/types";
import styles from "./Group.module.css"
import {EntitySpan} from "../EntitySpan/EntitySpan";
import {useGroups} from "../../contexts/GroupProvider";

interface Props {
  group: Group
}

const GroupBoxBase: FC<Props> = ({ group }) => {
  const {factories, findFactory} = useFactories()
  const {
    doNotSuggest,
    setFactories,
    baseFactories,
    exportedFactories,
    ignoredFactories,
    setIgnoredFactories,
    renameGroup,
    removeGroup,
    getInputType
  } = useGroups()
  const {
    name,
    exports,
    malls
  } = group

  const [isDeleteConfirm, setDeleteConfirm] = useState(false)

  const [inputs, intermediates] = useMemo<[string[], string[]]>(() => {
    const allProducingFactories = [...exports, ...malls]
    const prducingSet = new Set(allProducingFactories)
    const ignored = new Set(ignoredFactories)
    const base = new Set(baseFactories)
    const inputs = new Set<string>()
    const intermediates = new Set<string>()

    let next: string|undefined
    while (next = allProducingFactories.pop()) {
      const pres = Object.keys(findFactory(next)?.recipe?.prerequisites ?? {})
      for (const pre of pres) {
        if (exportedFactories.has(pre) || base.has(pre)) {
          if (!prducingSet.has(pre)) inputs.add(pre)
        } else if (!intermediates.has(pre)) {
          if (!prducingSet.has(pre)) intermediates.add(pre)
          allProducingFactories.push(pre)
        }
      }
    }
    return [
      Array.from(inputs).sort((a, b) => a.localeCompare(b)),
      Array.from(intermediates).sort((a, b) => a.localeCompare(b))
    ]
  }, [exports, malls, ignoredFactories, baseFactories, findFactory, exportedFactories])

  const [suggestionsExport, suggestionMall] = useMemo<[EnrichedEntity[], EnrichedEntity[]]>(() => {
    const selectedValues = Array.from(new Set([...exports, ...malls]))
    const availableIngredients = Array.from(new Set([...selectedValues, ...intermediates, ...inputs]))
    return factories
      .filter(factory => {
        if (!factory.recipe) return false
        if (selectedValues.includes(factory.href)) return false
        if (doNotSuggest.has(factory.href)) return false
        const prerequisites = Object.keys(factory.recipe.prerequisites ?? {})
        return prerequisites.every(pre => availableIngredients.includes(pre))
      })
      .reduce((acc, factory) =>
        (factory.usedBy?.length ?? 0) >= 3
          ? [[...acc[0], factory], acc[1]]
          : [acc[0], [...acc[1], factory]],
        [[], []] as [EnrichedEntity[], EnrichedEntity[]]
      )
  }, [exports, malls, intermediates, inputs, factories, doNotSuggest])

  const addFactory = useCallback((uid: string, type: Parameters<typeof setFactories>[2]) => {
    setFactories(name, [...group[type], uid], type)
  }, [group, name, setFactories])

  const setExportFactories = useCallback((factories: string[]) => setFactories(name, factories, 'exports'), [setFactories, name])
  const setMallFactories = useCallback((factories: string[]) => setFactories(name, factories, 'malls'), [setFactories, name])

  return <div className={styles.root}>
    <h3
      contentEditable={true}
      suppressContentEditableWarning={true}
      onBlur={event => {
        event.currentTarget.innerText = event.currentTarget.innerText.trim()
        renameGroup(name, event.currentTarget.innerText);
      }}
    >
      {name}
    </h3>
    <button
      className={styles.quit}
      onBlur={() => setDeleteConfirm(false)}
      onClick={() => !isDeleteConfirm ? setDeleteConfirm(true) : removeGroup(name)} style={{display: 'block'}}
    >
      {isDeleteConfirm ? 'Delete Group?' : 'X'}
    </button>
    <h4>Exported Factories</h4>
    <FactorySelect
      id={name+"-exports"}
      factories={exports}
      onSetFactories={setExportFactories}
    />
    <h4>Mall Factories</h4>
    <FactorySelect
      id={name+"-malls"}
      factories={malls}
      onSetFactories={setMallFactories}
    />
    { inputs.length ? <>
      <h4>Input Factories ({inputs.length})</h4>
      <div className={styles.flex}>
        { inputs.map(input => <EntitySpan
          key={input}
          value={input}
          state={getInputType(input)}
          onContextMenu={event => {
            event.preventDefault()
            setIgnoredFactories([...ignoredFactories, input])
          }}
          rightClickText={"Exclude this recipe from suggestions"}
        />) }
      </div>
    </> : null }
    { intermediates.length ? <>
      <h4>Intermediate Factories ({intermediates.length})</h4>
      <div className={styles.flex}>
        { intermediates.map(intermediate => <EntitySpan
          key={intermediate}
          value={intermediate}
          state={getInputType(intermediate)}
        />) }
      </div>
    </> : null }
    { suggestionsExport.length ? <>
      <h4>Suggestions (Export)</h4>
      <div className={styles.flex}>
        { suggestionsExport.map(suggestion => <EntitySpan
          key={suggestion.href}
          value={suggestion}
          onClick={() => addFactory(suggestion.href, 'exports')}
          onContextMenu={event => {
            event.preventDefault()
            setIgnoredFactories([...ignoredFactories, suggestion.href])
          }}
          leftClickText={"Add to exported factories"}
          rightClickText={"Exclude this recipe from suggestions"}
        />) }
      </div>
    </> : null }
    { suggestionMall.length ? <>
      <h4>Suggestions (Mall)</h4>
      <div className={styles.flex}>
        { suggestionMall.map(suggestion => <EntitySpan
          key={suggestion.href}
          value={suggestion}
          onClick={() => addFactory(suggestion.href, 'malls')}
          onContextMenu={event => {
            event.preventDefault()
            setIgnoredFactories([...ignoredFactories, suggestion.href])
          }}
          leftClickText={"Add to mall factories"}
          rightClickText={"Exclude this recipe from suggestions"}
        />) }
      </div>
    </> : null }
  </div>
}

export const GroupBox = memo(GroupBoxBase)
