import { useCallback, useEffect, useMemo, useState } from "react";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "~/components/ui/resizable";
import Tabs, { Tab } from "~/components/ui/tabs";
import FileViewer from "./file-viewer";
import trpc from "~/lib/trpc";
import EditorContext from "../context/editor";
import type { FileSchema } from "~/server/db/schema/file";
import Panel from "~/components/ui/panel";
import { useProjectContext } from "../context/project";
import Sidebar from "./sidebar";
import ConsoleLogger from "./console-logger";
import { useData } from "~/renderer/hooks";
import { Data } from "../+data";
import { useBreakpoint } from "~/hooks/useBreakpoint";
import StatusBar from "./status-bar";
import { FiTerminal } from "react-icons/fi";
import SettingsDialog from "./settings-dialog";
import FileIcon from "~/components/ui/file-icon";

const Editor = () => {
  const { project, initialFiles } = useData<Data>();
  const trpcUtils = trpc.useUtils();
  const projectCtx = useProjectContext();
  const [breakpoint] = useBreakpoint();

  const [curTabIdx, setCurTabIdx] = useState(0);
  const [curOpenFiles, setOpenFiles] = useState<number[]>(
    initialFiles.map((i) => i.id)
  );

  const openedFilesData = trpc.file.getAll.useQuery(
    { projectId: project.id, id: curOpenFiles },
    { enabled: curOpenFiles.length > 0, initialData: initialFiles }
  );
  const [openedFiles, setOpenedFiles] = useState<any[]>(initialFiles);

  const deleteFile = trpc.file.delete.useMutation({
    onSuccess: (file) => {
      trpcUtils.file.getAll.invalidate();
      onFileChanged(file);

      const openFileIdx = curOpenFiles.indexOf(file.id);
      if (openFileIdx >= 0) {
        onCloseFile(openFileIdx);
      }
    },
  });

  useEffect(() => {
    if (!initialFiles?.length || curOpenFiles.length > 0) {
      return;
    }

    initialFiles.forEach((file) => {
      onOpenFile(file.id, false);
    });

    return () => {
      setOpenFiles([]);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [initialFiles]);

  useEffect(() => {
    if (openedFilesData.data) {
      setOpenedFiles(openedFilesData.data);
    }
  }, [openedFilesData.data]);

  const onOpenFile = useCallback(
    (fileId: number, autoSwitchTab = true) => {
      const idx = curOpenFiles.indexOf(fileId);
      if (idx >= 0) {
        return setCurTabIdx(idx);
      }

      setOpenFiles((state) => {
        if (autoSwitchTab) {
          setCurTabIdx(state.length);
        }
        return [...state, fileId];
      });
    },
    [curOpenFiles]
  );

  const onDeleteFile = useCallback(
    (fileId: number) => {
      if (
        window.confirm("Are you sure want to delete this files?") &&
        !deleteFile.isPending
      ) {
        deleteFile.mutate(fileId);
      }
    },
    [deleteFile]
  );

  const onCloseFile = useCallback(
    (idx: number) => {
      const _f = [...curOpenFiles];
      _f.splice(idx, 1);
      setOpenFiles(_f);

      if (curTabIdx === idx) {
        setCurTabIdx(Math.max(0, idx - 1));
      }
    },
    [curOpenFiles, curTabIdx]
  );

  const onFileChanged = useCallback(
    (_file: Omit<FileSchema, "content">) => {
      openedFilesData.refetch();
    },
    [openedFilesData]
  );

  const tabs = useMemo(() => {
    let tabs: Tab[] = [];

    // opened files
    tabs = tabs.concat(
      curOpenFiles.map((fileId) => {
        const fileData = openedFiles?.find((i) => i.id === fileId);
        const filename = fileData?.filename || "...";

        return {
          title: filename,
          icon: <FileIcon file={{ isDirectory: false, filename }} />,
          render: () => <FileViewer id={fileId} />,
        };
      })
    );

    // show console tab on mobile
    if (breakpoint < 2) {
      tabs.push({
        title: "Console",
        icon: <FiTerminal />,
        render: () => <ConsoleLogger />,
        locked: true,
      });
    }

    return tabs;
  }, [curOpenFiles, openedFiles, breakpoint]);

  const PanelComponent = !projectCtx.isCompact ? Panel : "div";

  return (
    <EditorContext.Provider
      value={{
        onOpenFile,
        onFileChanged,
        onDeleteFile,
      }}
    >
      <PanelComponent className="h-full relative flex flex-col">
        <ResizablePanelGroup
          autoSaveId="veditor-panel"
          direction="horizontal"
          className="flex-1 order-2 md:order-1"
        >
          <Sidebar
            defaultSize={{ sm: 50, md: 25 }}
            defaultCollapsed={{ sm: true, md: false }}
            minSize={10}
            collapsible
            collapsedSize={0}
          />

          <ResizableHandle className="w-0" />

          <ResizablePanel defaultSize={{ sm: 100, md: 75 }}>
            <ResizablePanelGroup autoSaveId="code-editor" direction="vertical">
              <ResizablePanel defaultSize={{ sm: 100, md: 80 }} minSize={20}>
                <Tabs
                  tabs={tabs}
                  current={Math.min(Math.max(curTabIdx, 0), tabs.length - 1)}
                  onChange={setCurTabIdx}
                  onClose={onCloseFile}
                  className="h-full"
                />
              </ResizablePanel>

              {breakpoint >= 2 ? (
                <>
                  <ResizableHandle className="!h-0" />

                  <ResizablePanel
                    defaultSize={{ sm: 0, md: 20 }}
                    collapsible
                    collapsedSize={0}
                    minSize={10}
                  >
                    <ConsoleLogger />
                  </ResizablePanel>
                </>
              ) : null}
            </ResizablePanelGroup>
          </ResizablePanel>
        </ResizablePanelGroup>

        <StatusBar className="order-1 md:order-2" />
      </PanelComponent>

      <SettingsDialog />
    </EditorContext.Provider>
  );
};

export default Editor;