import { useAutoMemo } from "hooks.macro"
import { useEvent } from "@aet/hooks"
import { gql, useLazyQuery } from "~/generated/graphql"
import { closeFile } from "../../store/actions"
import { useDispatch, useSelector } from "../../store"
import { useFileSaver } from "../../hooks/useSaveFile"
import { ConfirmResult, confirmClose } from "../useConfirmClose"
import type { ReduxFile } from "../../store/state"

export const EditorTabQuery = gql<"EditorTabQuery">`
  query EditorTabQuery($id: ID!) {
    file(id: $id) {
      id
      name
      nameLanguage
    }
  }
`

export function useTabsCloser(tabs: ReduxFile[]) {
  const close = useTabCloser()

  const onCloseMultipleTabs = useEvent(async (fileIds: string[]) => {
    for (const fileId of fileIds) {
      if (!(await close(fileId))) {
        return
      }
    }
  })

  const onCloseTab = useEvent(async (fileId: string, name?: string) => {
    await close(fileId, name)
  })
  const onCloseOthers = useEvent(async (fileId: string) => {
    await onCloseMultipleTabs(tabs.filter(t => t.id !== fileId).map(t => t.id))
  })
  const onCloseRight = useEvent(async (fileId: string) => {
    const index = tabs.findIndex(t => t.id === fileId)
    await onCloseMultipleTabs(tabs.slice(index + 1).map(t => t.id))
  })
  const onCloseAll = useEvent(async () => {
    await onCloseMultipleTabs(tabs.map(t => t.id))
  })

  return useAutoMemo({
    onCloseMultipleTabs,
    onCloseTab,
    onCloseOthers,
    onCloseRight,
    onCloseAll,
  })
}

export function useTabCloser() {
  const dirtyFileIds = useSelector(s => s.dirtyFileIds)
  const dispatch = useDispatch()
  const save = useFileSaver()
  const [fetchFileData] = useLazyQuery(EditorTabQuery, { fetchPolicy: "cache-only" })

  const close = useEvent(async (fileId: string, fileName?: string) => {
    if (!fileId) {
      return false
    }
    if (!dirtyFileIds.has(fileId)) {
      dispatch(closeFile(fileId))
      return true
    }

    if (!fileName) {
      const { data } = await fetchFileData({ variables: { id: fileId } })
      if (!data?.file) {
        return false
      }
      fileName = data.file.name
    }

    switch (await confirmClose(fileName)) {
      case ConfirmResult.Save:
        await save(fileId)
        dispatch(closeFile(fileId))
        return true
      case ConfirmResult.Discard:
        dispatch(closeFile(fileId))
        return true
      case ConfirmResult.Cancel:
        return false
    }
  })

  return close
}
