import {useState} from 'react';

import {usePacket} from '@/context/client.js';
import {useEcs, useEcsTick} from '@/context/ecs.js';
import {parseLetters} from '@/dialogue.js';

import Entity from './entity.jsx';

export default function Entities({
  camera,
  scale,
  setChatMessages,
  setMonopolizers,
}) {
  const [ecs] = useEcs();
  const [entities, setEntities] = useState({});
  usePacket('EcsChange', async () => {
    setEntities({});
  }, [setEntities]);
  useEcsTick((payload) => {
    if (!ecs) {
      return;
    }
    const deleting = {};
    const updating = {};
    for (const id in payload) {
      if ('1' === id) {
        continue;
      }
      const update = payload[id];
      if (false === update) {
        deleting[id] = true;
        continue;
      }
      updating[id] = ecs.get(id);
      const {dialogue} = update.Interlocutor || {};
      if (dialogue) {
        const {dialogues} = updating[id].Interlocutor;
        for (const key in dialogue) {
          dialogues[key] = dialogue[key];
          dialogues[key].letters = parseLetters(dialogues[key].body);
          setChatMessages((chatMessages) => ({
            [[id, key].join('-')]: dialogues[key].letters,
            ...chatMessages,
          }));
          const skipListeners = new Set();
          dialogues[key].addSkipListener = (listener) => {
            skipListeners.add(listener);
            return () => {
              skipListeners.delete(listener);
            }
          }
          const monopolizer = {
            trigger: () => {
              for (const listener of skipListeners) {
                listener();
              }
            },
          };
          if (dialogues[key].monopolizer) {
            setMonopolizers((monopolizers) => [...monopolizers, monopolizer]);
          }
          dialogues[key].onClose = () => {
            setEntities((entities) => ({
              ...entities,
              [id]: ecs.rebuild(id),
            }));
            if (dialogues[key].monopolizer) {
              setMonopolizers((monopolizers) => {
                const index = monopolizers.indexOf(monopolizer);
                if (-1 === index) {
                  return monopolizers;
                }
                monopolizers.splice(index, 1);
                return [...monopolizers];
              });
            }
            delete dialogues[key];
          };
        }
      }
    }
    setEntities((entities) => {
      for (const id in deleting) {
        delete entities[id];
      }
      return {
        ...entities,
        ...updating,
      };
    });
  }, [ecs, setMonopolizers]);
  const renderables = [];
  for (const id in entities) {
    renderables.push(
      <Entity
        camera={camera}
        entity={entities[id]}
        key={id}
        scale={scale}
      />
    );
  }
  return (
    <>
      {renderables}
    </>
  );
}
