import { FC, memo, useCallback, useMemo, useState } from 'react'
import { FactorySelect } from '../FactorySelect/FactorySelect'
import { useFactories } from '../../../src/hooks/useFactories'
import { EnrichedEntity, Group } from '../../../src/types'
import styles from './GroupBox.module.css'
import { EntitySpan } from '../EntitySpan/EntitySpan'
import { useGroups } from '../../contexts/GroupProvider'
import { calculateInputs } from '../../../src/calculateInputs'
import { fixedEncodeURIComponent, uniquify } from '../../../src/utils'
import Link from 'next/link'
import { useRouter } from 'next/router'

interface Props {
  group: Group
}

const GroupBoxBase: FC<Props> = ({ group }) => {
  const router = useRouter()
  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(() => {
    const allProducingFactories = [...exports, ...malls]
    return calculateInputs(allProducingFactories, baseFactories, exportedFactories, findFactory)
  }, [exports, malls, baseFactories, findFactory, exportedFactories])

  const [suggestionsExport, suggestionMall] = useMemo<[EnrichedEntity[], EnrichedEntity[]]>(() => {
    const selectedValues = uniquify([...exports, ...malls])
    const availableIngredients = uniquify([...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(
    (exportFactories: string[]) => setFactories(name, exportFactories, 'exports'),
    [setFactories, name]
  )
  const setMallFactories = useCallback(
    (mallFactories: string[]) => setFactories(name, mallFactories, '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>
      <Link
        href={{
          pathname: `/visualize/${fixedEncodeURIComponent(group.name)}`,
          query: router.query
        }}
      >
        👁
      </Link>
      <button
        className={styles.quit}
        onBlur={() => setDeleteConfirm(false)}
        onClick={() => (!isDeleteConfirm ? setDeleteConfirm(true) : removeGroup(name))}
        style={{ display: 'block' }}
      >
        {isDeleteConfirm ? 'Delete GroupBox?' : '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)
