import { nextTick, unref } from "vue";

  export const useScroll = () => {
    const resolveElement = (value) => {
      const instance = unref(value);

      return instance?.$el ?? instance ?? null;
    };

    const resolveContainer = (targetElement, containerRef) => {
      const containerInstance = unref(containerRef);

      if (typeof containerInstance?.setScrollPosition === "function") {
        return {
          instance: containerInstance,
          element:
            containerInstance.getScrollTarget?.() ??
            containerInstance.$el?.querySelector?.(
              ".q-scrollarea__container",
            ) ??
            containerInstance.$el,
          isQuasar: true,
        };
      }

      const providedElement = resolveElement(containerRef);

      const detectedElement = targetElement?.closest?.(
        ".q-scrollarea__container, .scroll, .scroll-y",
      );

      const element =
        providedElement ??
        detectedElement ??
        document.scrollingElement ??
        document.documentElement;

      return {
        instance: element,
        element,
        isQuasar: false,
      };
    };

    //

    const calculatePosition = (targetElement, containerElement, offset) => {
      const targetRect = targetElement.getBoundingClientRect();

      const isDocumentContainer =
        containerElement === document.body ||
        containerElement === document.documentElement ||
        containerElement === document.scrollingElement;

      if (isDocumentContainer) {
        return Math.max(
          0,
          targetRect.top + window.scrollY - offset,
        );
      }

      const containerRect = containerElement.getBoundingClientRect();

      return Math.max(
        0,
        targetRect.top -
          containerRect.top +
          containerElement.scrollTop -
          offset,
      );
    };

    const scrollToComponent = (targetRef, containerRef, options = {}) => {
      const { offset = 150, duration = 150, behavior = "smooth" } = options;

      const targetElement = resolveElement(targetRef);

      if (!targetElement) {
        console.warn("useScroll: Target element not found");
        return false;
      }

      const container = resolveContainer(targetElement, containerRef);

      const containerElement = container.element;

      if (!containerElement) {
        console.warn("useScroll: Container element not found");

        return false;
      }

      const isDocumentContainer =
        containerElement === document.body ||
        containerElement === document.documentElement ||
        containerElement === document.scrollingElement;

      if (
        !isDocumentContainer &&
        !containerElement.contains(targetElement)
      ) {
        console.warn("useScroll: Target is not inside the container");
        return false;
      }

      try {
        const targetPosition = calculatePosition(
          targetElement,
          containerElement,
          offset,
        );

        if (container.isQuasar) {
          container.instance.setScrollPosition(
            "vertical",
            targetPosition,
            duration,
          );
        } else if (isDocumentContainer) {
          window.scrollTo({
            top: targetPosition,
            behavior,
          });
        } else {
          containerElement.scrollTo({
            top: targetPosition,
            behavior,
          });
        }

        return true;
      } catch (error) {
        console.error("useScroll: Error while scrolling", error);
        return false;
      }
    };

    const scrollToFirstError = async (
      formRef,
      containerRef,
      options = {},
    ) => {
      await nextTick();

      const forms = unref(formRef);

      const formInstances = Array.isArray(forms) ? forms : [forms];

      for (const formInstance of formInstances) {
        const formElement = resolveElement(formInstance);

        const errorElement =
          formElement?.matches?.(".q-field--error")
            ? formElement
            : formElement?.querySelector?.(".q-field--error");

        if (errorElement) {
          const scrollFn = options.scrollFn ?? scrollToComponent;

          return scrollFn(errorElement, containerRef, options);
        }
      }

      return false;
    };

    return {
      scrollToComponent,
      scrollToFirstError,
    };
  };
