import type { NextPage } from 'next'
import Head from 'next/head'
import {useGroups} from "../../components/contexts/GroupProvider";
import {useFactories} from "../../src/hooks/useFactories";
import {ProducingGraph} from "../../components/shared/ProducingGraph/ProducingGraph";
import {useMemo} from "react";
import {calculateInputs} from "../../src/calculateInputs";
import {useRouter} from "next/router";
import {groupBy, isNonNullable, uniquify} from "../../src/utils";
import {EnrichedEntity, Recipe} from "../../src/types";
import {DetailGraphNode, NodeDetails} from "../../components/visualize/NodeDetails/NodeDetails";



const Page: NextPage = () => {
  const {query: {name}} = useRouter()
  const {
    exportedFactories,
    baseFactories,
    ignoredFactories,
    groups
  } = useGroups()
  const {
    findFactory
  } = useFactories()

  const group = typeof name === 'string' ? groups[name] : undefined

  const [inputFactories, intermediateFactories] = useMemo<ReturnType<typeof calculateInputs>>(() => {
    if (!group) return [[], []]
    return calculateInputs(
      [...group.exports, ...group.malls],
      ignoredFactories,
      baseFactories,
      exportedFactories,
      findFactory
    )
  }, [baseFactories, exportedFactories, findFactory, group, ignoredFactories])

  const producingNodes: DetailGraphNode[] = useMemo(() => {
    if (!group) return []
    const nodes = uniquify([...intermediateFactories, ...group.exports, ...group.malls])
      .map(findFactory)
      .filter(isNonNullable)
      .map((factory: EnrichedEntity) => ({
        inputs: Object.keys(factory.recipe?.prerequisites ?? {}).sort((a, b) => a.localeCompare(b)),
        outputs: Object.keys(factory.recipe?.output ?? {}).sort((a, b) => a.localeCompare(b)),
        name: factory.name,
        recipes: [factory.recipe]
      } as DetailGraphNode))
    return Object
      .values(groupBy(nodes, node => node.inputs.join()))
      .map(nodesOfInput => ({
        inputs: nodesOfInput[0].inputs,
        outputs: uniquify(nodesOfInput.flatMap(node => node.outputs)),
        name: nodesOfInput.map(node => node.name).join(', '),
        recipes: nodesOfInput.flatMap(node => node.recipes)
      } as DetailGraphNode))
  }, [findFactory, group, intermediateFactories])

  return (
    <>
      <Head>
        <title>Factorio Microservices</title>
        <meta name="description" content="Create Factorio microservices" />
        <link rel="icon" href="/public/favicon.ico" />
      </Head>
      <main>
        <h1>Factorio Microservices</h1>
        <ProducingGraph
          nodes={producingNodes}
          inputs={inputFactories}
          outputs={group?.exports}
          childType={NodeDetails}
          />
      </main>
    </>
  )
}

export async function getServerSideProps() {
  return { props: { bodyClassName: 'scroll' } };
}

export default Page
