import { useEffect, useMemo, useState } from 'react';

import { ipcChannels } from '../../../shared/ipc/contracts';
import type { NpcMapSpawnDragState } from '../../../shared/types';
import { asNpcId } from '../../../shared/types/ids';
import { getDndApi } from '../dndApi';

const EMPTY: NpcMapSpawnDragState = {
  dragging: false,
  npcId: null,
  hoverNx: null,
  hoverNy: null,
};

export function useNpcMapSpawnDrag(): [
  NpcMapSpawnDragState,
  {
    beginDrag: (npcId: string) => Promise<void>;
    setHover: (nx: number | null, ny: number | null) => Promise<void>;
    commit: () => Promise<boolean>;
    cancel: () => Promise<void>;
  },
] {
  const api = getDndApi();
  const [state, setState] = useState<NpcMapSpawnDragState>(EMPTY);

  useEffect(() => {
    void api.invoke(ipcChannels.npcMapSpawn.getState, {}).then(({ state: s }) => {
      setState(s);
    });
    return api.on(ipcChannels.npcMapSpawn.stateChanged, ({ state: s }) => {
      setState(s);
    });
  }, [api]);

  const apiWrap = useMemo(
    () => ({
      beginDrag: async (npcId: string) => {
        await api.invoke(ipcChannels.npcMapSpawn.beginDrag, { npcId: asNpcId(npcId) });
      },
      setHover: async (nx: number | null, ny: number | null) => {
        await api.invoke(ipcChannels.npcMapSpawn.setHover, { nx, ny });
      },
      commit: async () => {
        const res = await api.invoke(ipcChannels.npcMapSpawn.commit, {});
        return Boolean(res.spawned);
      },
      cancel: async () => {
        await api.invoke(ipcChannels.npcMapSpawn.cancel, {});
      },
    }),
    [api],
  );

  return [state, apiWrap];
}
