"use client";

import { type FormEvent, useEffect, useRef, useState } from "react";

import type { FeedbackCategory } from "@/data/schemas/feedback";
import { submitFeedback } from "@/lib/feedback";

import { createFeedbackContext } from "./feedback-context";
import {
  FEEDBACK_IMAGE_LIMIT,
  prepareFeedbackImage,
} from "./feedback-image";

export const FEEDBACK_CONTENT_MIN_LENGTH = 10;
export const FEEDBACK_CONTENT_MAX_LENGTH = 2000;

export interface FeedbackImageItem {
  id: string;
  file: File;
  previewUrl: string;
}

export function useFeedbackSubmission() {
  const [category, setCategory] = useState<FeedbackCategory>("problem");
  const [content, setContent] = useState("");
  const [images, setImages] = useState<FeedbackImageItem[]>([]);
  const [isPreparingImages, setIsPreparingImages] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [feedbackId, setFeedbackId] = useState<string | null>(null);
  const imagesRef = useRef(images);

  useEffect(() => {
    imagesRef.current = images;
  }, [images]);

  useEffect(
    () => () => {
      imagesRef.current.forEach((image) => URL.revokeObjectURL(image.previewUrl));
    },
    [],
  );

  const addImages = async (files: FileList | readonly File[]) => {
    if (isPreparingImages || isSubmitting) return;
    const availableSlots = FEEDBACK_IMAGE_LIMIT - images.length;
    if (availableSlots <= 0) {
      setErrorMessage(`You can add up to ${FEEDBACK_IMAGE_LIMIT} images.`);
      return;
    }

    const selectedFiles = Array.from(files);
    const filesToPrepare = selectedFiles.slice(0, availableSlots);
    const nextImages: FeedbackImageItem[] = [];
    const errors: string[] = [];
    setIsPreparingImages(true);
    setErrorMessage(null);

    for (const file of filesToPrepare) {
      try {
        const preparedFile = await prepareFeedbackImage(file);
        nextImages.push({
          id: createImageId(),
          file: preparedFile,
          previewUrl: URL.createObjectURL(preparedFile),
        });
      } catch (error) {
        errors.push(error instanceof Error ? error.message : "Image processing failed.");
      }
    }

    if (selectedFiles.length > availableSlots) {
      errors.push(`You can add up to ${FEEDBACK_IMAGE_LIMIT} images.`);
    }
    setImages((current) => [...current, ...nextImages]);
    setErrorMessage(errors[0] ?? null);
    setIsPreparingImages(false);
  };

  const removeImage = (id: string) => {
    if (isSubmitting) return;
    setImages((current) => {
      const image = current.find((item) => item.id === id);
      if (image) URL.revokeObjectURL(image.previewUrl);
      return current.filter((item) => item.id !== id);
    });
    setErrorMessage(null);
  };

  const submit = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (isSubmitting || isPreparingImages) return;

    const normalizedContent = content.trim();
    const validationError = validateFeedbackContent(normalizedContent);
    if (validationError) {
      setErrorMessage(validationError);
      return;
    }

    setIsSubmitting(true);
    setErrorMessage(null);
    const result = await submitFeedback({
      category,
      content: normalizedContent,
      context: createFeedbackContext(),
      images: images.map((image) => image.file),
    });

    if (result.success) {
      setFeedbackId(result.data.feedbackId);
    } else {
      setErrorMessage(result.error.message || "Feedback could not be sent. Please try again.");
    }
    setIsSubmitting(false);
  };

  return {
    category,
    content,
    images,
    isPreparingImages,
    isSubmitting,
    errorMessage,
    feedbackId,
    canSubmit:
      validateFeedbackContent(content.trim()) === null &&
      !isPreparingImages &&
      !isSubmitting,
    setCategory,
    setContent,
    addImages,
    removeImage,
    submit,
  };
}

export function validateFeedbackContent(content: string): string | null {
  if (content.length < FEEDBACK_CONTENT_MIN_LENGTH) {
    return `Please enter at least ${FEEDBACK_CONTENT_MIN_LENGTH} characters.`;
  }
  if (content.length > FEEDBACK_CONTENT_MAX_LENGTH) {
    return `Feedback cannot exceed ${FEEDBACK_CONTENT_MAX_LENGTH} characters.`;
  }
  return null;
}

function createImageId(): string {
  return typeof crypto !== "undefined" && "randomUUID" in crypto
    ? crypto.randomUUID()
    : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
}
