"use client";

import { fileService } from "@/lib/api";
import { extractFileId } from "@/lib/api/config";
import { userService } from "@/lib/api/services/user-services";
import {
  ALLOWED_IMAGE_FILE_TYPES,
  MAX_IMAGE_FILE_SIZE,
  validateImageFile,
} from "@/utils/shared";
import { ChangeEvent, useEffect, useState } from "react";
import { useForm } from "react-hook-form";

interface IProps {
  /** Currently stored URL for this field (empty string when none). */
  value?: string;
  /** Persist the uploaded file URL (or empty string when cleared). */
  onChange: (url: string) => void;
  category?: string;
  tags?: string[];
  description?: string;
  allowedTypes?: string[];
  maxSize?: number;
}

interface IFileFieldValues {
  file?: FileList;
}

/**
 * Reusable upload lifecycle for a single image field that stores a URL string.
 * Generalizes the profile-image flow from `useCreateAdminPresenter` so any form
 * (e.g. marketing card icons) can drop in a `FileImageUploadCard`.
 */
export const useImageUploadFieldPresenter = ({
  value,
  onChange,
  category = "cms",
  tags = ["cms", "marketing"],
  description = "Marketing media",
  allowedTypes = ALLOWED_IMAGE_FILE_TYPES,
  maxSize = MAX_IMAGE_FILE_SIZE,
}: IProps) => {
  const [selectedFileName, setSelectedFileName] = useState<string>("");
  const [selectedFileSize, setSelectedFileSize] = useState<number | null>(null);
  const [isUploading, setIsUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState<number>(0);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [errorMessage, setErrorMessage] = useState<string | undefined>();

  const { register, setValue } = useForm<IFileFieldValues>({
    defaultValues: { file: undefined },
  });

  // Build a previewable source from the stored value. Backend file URLs are
  // auth-protected, so fetch them through the proxy into a local object URL.
  useEffect(() => {
    if (!value) {
      setPreviewUrl(null);
      return;
    }
    if (!extractFileId(value)) {
      setPreviewUrl(value);
      return;
    }

    let cancelled = false;
    userService
      .fetchFileObjectUrl(value)
      .then((objectUrl) => {
        if (cancelled) {
          URL.revokeObjectURL(objectUrl);
          return;
        }
        setPreviewUrl(objectUrl);
      })
      .catch(() => {
        // Leave the preview empty rather than showing a broken image.
      });

    return () => {
      cancelled = true;
    };
  }, [value]);

  // Revoke local blob previews when they are replaced or unmounted.
  useEffect(() => {
    return () => {
      if (previewUrl?.startsWith("blob:")) {
        URL.revokeObjectURL(previewUrl);
      }
    };
  }, [previewUrl]);

  const resetSelection = () => {
    setSelectedFileName("");
    setSelectedFileSize(null);
    setUploadProgress(0);
  };

  const onFileChange = async (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    const input = event.target;

    if (!file) {
      resetSelection();
      setErrorMessage(undefined);
      return;
    }

    const validationError = validateImageFile({ file, allowedTypes, maxSize });
    if (validationError) {
      setErrorMessage(validationError);
      input.value = "";
      return;
    }

    setErrorMessage(undefined);
    setSelectedFileName(file.name);
    setSelectedFileSize(file.size);
    setIsUploading(true);
    setUploadProgress(0);
    // Preview the local file directly while the upload runs.
    setPreviewUrl(URL.createObjectURL(file));

    try {
      const url = await fileService.uploadFile({
        file,
        category,
        tags,
        description,
        onProgress: setUploadProgress,
      });
      setUploadProgress(100);
      onChange(url);
    } catch {
      resetSelection();
      setPreviewUrl(null);
      setValue("file", undefined);
      onChange("");
      setErrorMessage("Failed to upload image");
      input.value = "";
    } finally {
      setIsUploading(false);
    }
  };

  const clear = () => {
    setValue("file", undefined);
    resetSelection();
    setPreviewUrl(null);
    setErrorMessage(undefined);
    onChange("");
  };

  const fileRegister = register("file", { onChange: onFileChange });

  return {
    fileRegister,
    isUploading,
    uploadProgress,
    selectedFileName,
    selectedFileSize,
    previewUrl,
    errorMessage,
    clear,
  };
};
