import { useCallback, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import apiClient from "@app/services/apiClient";
import type { ToolOperationHook } from "@app/hooks/tools/shared/useToolOperation";
import type { StirlingFile } from "@app/types/fileContext";
import { extractErrorMessage } from "@app/utils/toolErrorHandler";
import type { ShowJSParameters } from "@app/hooks/tools/showJS/useShowJSParameters";

export interface ShowJSOperationHook extends ToolOperationHook<ShowJSParameters> {
  scriptText: string | null;
}

export const useShowJSOperation = (): ShowJSOperationHook => {
  const { t } = useTranslation();

  const [isLoading, setIsLoading] = useState(false);
  const [status, setStatus] = useState("");
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [files, setFiles] = useState<File[]>([]);
  const [downloadUrl, setDownloadUrl] = useState<string | null>(null);
  const [downloadFilename, setDownloadFilename] = useState("");
  const [scriptText, setScriptText] = useState<string | null>(null);

  const cancelRequested = useRef(false);
  const previousUrl = useRef<string | null>(null);

  const cleanupDownloadUrl = useCallback(() => {
    if (previousUrl.current) {
      URL.revokeObjectURL(previousUrl.current);
      previousUrl.current = null;
    }
  }, []);

  const resetResults = useCallback(() => {
    cancelRequested.current = false;
    setScriptText(null);
    setFiles([]);
    cleanupDownloadUrl();
    setDownloadUrl(null);
    setDownloadFilename("");
    setStatus("");
    setErrorMessage(null);
  }, [cleanupDownloadUrl]);

  const clearError = useCallback(() => {
    setErrorMessage(null);
  }, []);

  const executeOperation = useCallback(
    async (_params: ShowJSParameters, selectedFiles: StirlingFile[]) => {
      if (selectedFiles.length === 0) {
        setErrorMessage(t("noFileSelected", "No file loaded"));
        return;
      }

      cancelRequested.current = false;
      setIsLoading(true);
      setStatus(t("showJS.processing", "Extracting JavaScript..."));
      setErrorMessage(null);
      setScriptText(null);
      setFiles([]);
      cleanupDownloadUrl();
      setDownloadUrl(null);
      setDownloadFilename("");

      try {
        const file = selectedFiles[0];
        const formData = new FormData();
        formData.append("fileInput", file);

        const response = await apiClient.post(
          "/api/v1/misc/show-javascript",
          formData,
          {
            responseType: "text",
          },
        );

        const text: string =
          typeof response.data === "string" ? response.data : "";
        setScriptText(text);

        // Optional: prepare a downloadable file
        const outFile = new File(
          [text],
          (file.name?.replace(/\.[^.]+$/, "") || "extracted") + ".js",
          {
            type: "application/javascript",
          },
        );
        setFiles([outFile]);
        const blobUrl = URL.createObjectURL(outFile);
        previousUrl.current = blobUrl;
        setDownloadUrl(blobUrl);
        setDownloadFilename(outFile.name);

        setStatus(t("showJS.done", "JavaScript extracted"));
      } catch (error: unknown) {
        setErrorMessage(extractErrorMessage(error));
        setStatus("");
      } finally {
        setIsLoading(false);
      }
    },
    [t, cleanupDownloadUrl],
  );

  const cancelOperation = useCallback(() => {
    cancelRequested.current = true;
    setIsLoading(false);
    setStatus(t("operationCancelled", "Operation cancelled"));
  }, [t]);

  const undoOperation = useCallback(async () => {
    // No-op for this tool
    setStatus(t("nothingToUndo", "Nothing to undo"));
  }, [t]);

  return {
    // State (align with ToolOperationHook)
    files,
    thumbnails: [],
    isGeneratingThumbnails: false,
    downloadUrl,
    downloadFilename,
    isLoading,
    status,
    errorMessage,
    progress: null,

    // Custom state
    scriptText,

    // Actions
    executeOperation,
    resetResults,
    clearError,
    cancelOperation,
    undoOperation,
  };
};
