import { useCallback, useState } from "react";
import { baseApi } from "../base-api";
import { resolveTokenFromStorage } from "../session";

export interface UploadFileInfo {
  bucket: string;
  fileName: string;
  contentType: string;
  originalname: string;
  size: number;
}

export interface UploadKeyResponse {
  fileInfo: UploadFileInfo;
  presigned: string;
}

const fileUploadApi = baseApi.injectEndpoints({
  endpoints: (builder) => ({
    getFileUploadKey: builder.mutation<
      UploadKeyResponse,
      { endpoint: string; file: File }
    >({
      query: ({ endpoint, file }) => ({
        url: endpoint,
        method: "POST",
        body: {
          fileName: file.name,
          contentType: file.type || "application/octet-stream",
          size: file.size,
          originalname: file.name,
        },
      }),
    }),
  }),
  overrideExisting: false,
});

export const { useGetFileUploadKeyMutation } = fileUploadApi;

export const STORAGE_UPLOAD_ERROR = "STORAGE_UPLOAD_ERROR";
export const STORAGE_UPLOAD_TOO_LARGE = "STORAGE_UPLOAD_TOO_LARGE";

export function isStorageUploadError(error: unknown): error is Error & {
  message: typeof STORAGE_UPLOAD_ERROR | typeof STORAGE_UPLOAD_TOO_LARGE;
} {
  return (
    error instanceof Error &&
    (error.message === STORAGE_UPLOAD_ERROR ||
      error.message === STORAGE_UPLOAD_TOO_LARGE)
  );
}

// Bare fetch on purpose: this PUT targets the presigned storage URL directly, not
// VITE_BASE_API_URL, so it must not go through baseApi/fetchBaseQuery.
async function uploadToPresigned(
  file: File,
  presignedUrl: string,
): Promise<void> {
  if (!presignedUrl) throw new Error(STORAGE_UPLOAD_ERROR);

  const token = resolveTokenFromStorage();
  const res = await fetch(presignedUrl, {
    method: "PUT",
    body: file,
    headers: {
      "Content-Type": file.type || "application/octet-stream",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
  });

  if (res.status === 413) throw new Error(STORAGE_UPLOAD_TOO_LARGE);
  if (!res.ok) throw new Error(STORAGE_UPLOAD_ERROR);
}

export function useDocumentUpload() {
  const [getFileUploadKey, mutationState] = useGetFileUploadKeyMutation();
  // Spans both steps (key request + presigned PUT) — mutationState.isLoading alone
  // would drop to false once the key request resolves, before the file PUT finishes.
  const [isUploading, setIsUploading] = useState(false);

  const upload = useCallback(
    async (file: File, endpoint = "/documents/get-file-upload-key"): Promise<UploadKeyResponse> => {
      setIsUploading(true);
      try {
        const { presigned, fileInfo } = await getFileUploadKey({
          endpoint,
          file,
        }).unwrap();
        await uploadToPresigned(file, presigned);
        return { presigned, fileInfo };
      } finally {
        setIsUploading(false);
      }
    },
    [getFileUploadKey],
  );

  return {
    upload,
    isUploading,
    error: mutationState.error,
    reset: mutationState.reset,
  };
}
