"use client";

import { useEffect, useRef, useState } from "react";
import { usePathname } from "next/navigation";

type DisabledElement = {
  element: HTMLElement;
  restore: () => void;
};

function isModifiedClick(event: MouseEvent) {
  return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0;
}

function shouldHandleAnchor(anchor: HTMLAnchorElement) {
  const href = anchor.getAttribute("href");
  if (!href || href.startsWith("#")) return false;
  if (anchor.target && anchor.target !== "_self") return false;
  if (anchor.hasAttribute("download")) return false;

  try {
    const url = new URL(anchor.href, window.location.href);
    if (url.origin !== window.location.origin) return false;
    if (url.pathname === window.location.pathname && url.search === window.location.search && url.hash) return false;
    if (url.pathname === window.location.pathname && url.search === window.location.search) return false;
    return true;
  } catch {
    return false;
  }
}

function disableElement(element: HTMLElement): DisabledElement {
  if (element instanceof HTMLButtonElement || element instanceof HTMLInputElement) {
    const prevDisabled = element.disabled;
    element.disabled = true;
    element.dataset.navDisabled = "true";
    return {
      element,
      restore: () => {
        element.disabled = prevDisabled;
        delete element.dataset.navDisabled;
      },
    };
  }

  const prevPointerEvents = element.style.pointerEvents;
  const prevOpacity = element.style.opacity;
  const prevAriaDisabled = element.getAttribute("aria-disabled");
  element.style.pointerEvents = "none";
  element.style.opacity = "0.6";
  element.setAttribute("aria-disabled", "true");
  element.dataset.navDisabled = "true";
  return {
    element,
    restore: () => {
      element.style.pointerEvents = prevPointerEvents;
      element.style.opacity = prevOpacity;
      if (prevAriaDisabled === null) {
        element.removeAttribute("aria-disabled");
      } else {
        element.setAttribute("aria-disabled", prevAriaDisabled);
      }
      delete element.dataset.navDisabled;
    },
  };
}

function softDisableElement(element: HTMLElement): DisabledElement {
  const prevPointerEvents = element.style.pointerEvents;
  const prevOpacity = element.style.opacity;
  const prevAriaDisabled = element.getAttribute("aria-disabled");
  element.style.pointerEvents = "none";
  element.style.opacity = "0.6";
  element.setAttribute("aria-disabled", "true");
  element.dataset.navDisabled = "true";
  return {
    element,
    restore: () => {
      element.style.pointerEvents = prevPointerEvents;
      element.style.opacity = prevOpacity;
      if (prevAriaDisabled === null) {
        element.removeAttribute("aria-disabled");
      } else {
        element.setAttribute("aria-disabled", prevAriaDisabled);
      }
      delete element.dataset.navDisabled;
    },
  };
}

export function RouteFeedback() {
  const pathname = usePathname();
  const [pending, setPending] = useState(false);
  const [progress, setProgress] = useState(0);
  const [ready, setReady] = useState(false);
  const disabledElementsRef = useRef<DisabledElement[]>([]);
  const fallbackTimeoutRef = useRef<number | null>(null);
  const pendingRef = useRef(false);
  const routeSnapshotRef = useRef("");

  useEffect(() => {
    pendingRef.current = pending;
  }, [pending]);

  useEffect(() => {
    const id = window.setTimeout(() => setReady(true), 0);
    return () => window.clearTimeout(id);
  }, []);

  useEffect(() => {
    if (!pending) return;

    let frame = 0;
    let active = true;

    const tick = () => {
      setProgress((current) => {
        if (!active) return current;
        const target = current < 35 ? current + 6 : current < 70 ? current + 2.5 : current < 88 ? current + 0.8 : current;
        return Math.min(target, 90);
      });
      frame = window.setTimeout(tick, 240);
    };

    tick();

    return () => {
      active = false;
      window.clearTimeout(frame);
    };
  }, [pending]);

  useEffect(() => {
    if (!pending) return;

    const currentRoute = `${pathname}${window.location.search}`;
    if (currentRoute === routeSnapshotRef.current) return;

    const complete = window.setTimeout(() => {
      setProgress(100);
    }, 0);
    const settle = window.setTimeout(() => {
      setPending(false);
      setProgress(0);
      disabledElementsRef.current.forEach((item) => item.restore());
      disabledElementsRef.current = [];
      if (fallbackTimeoutRef.current !== null) {
        window.clearTimeout(fallbackTimeoutRef.current);
        fallbackTimeoutRef.current = null;
      }
    }, 240);

    return () => {
      window.clearTimeout(complete);
      window.clearTimeout(settle);
    };
  }, [pathname, pending]);

  useEffect(() => {
    const startPending = (element?: HTMLElement | null, soft = false) => {
      if (pendingRef.current) return;

      routeSnapshotRef.current = `${pathname}${window.location.search}`;

      if (element) {
        disabledElementsRef.current.forEach((item) => {
          if (item.element === element) item.restore();
        });
        disabledElementsRef.current = disabledElementsRef.current.filter((item) => item.element !== element);
        disabledElementsRef.current.push(soft ? softDisableElement(element) : disableElement(element));
      }

      setPending(true);
      setProgress((current) => (current > 0 ? current : 12));

      if (fallbackTimeoutRef.current !== null) {
        window.clearTimeout(fallbackTimeoutRef.current);
      }

      fallbackTimeoutRef.current = window.setTimeout(() => {
        setPending(false);
        setProgress(0);
        disabledElementsRef.current.forEach((item) => item.restore());
        disabledElementsRef.current = [];
        fallbackTimeoutRef.current = null;
      }, 12000);
    };

    const handleClick = (event: MouseEvent) => {
      if (!ready) return;
      if (isModifiedClick(event)) return;
      const target = event.target as HTMLElement | null;

      const submitButton = target?.closest('button[type="submit"], input[type="submit"]') as HTMLElement | null;
      if (submitButton) {
        const localForm = submitButton.closest("form[data-local-submit='true']");
        if (localForm) return;

        startPending(submitButton, true);
        return;
      }

      const anchor = target?.closest("a[href]") as HTMLAnchorElement | null;
      if (!anchor || !shouldHandleAnchor(anchor)) return;
      startPending(anchor);
    };

    const handleSubmit = (event: Event) => {
      if (!ready) return;
      if (event.defaultPrevented) return;
      const submitEvent = event as SubmitEvent;
      const form = submitEvent.target as HTMLFormElement | null;
      if (!form || form.method.toLowerCase() !== "post") return;
      if (form.dataset.localSubmit === "true") return;
      const submitter = submitEvent.submitter instanceof HTMLElement ? submitEvent.submitter : null;
      startPending(submitter);
    };

    document.addEventListener("click", handleClick, true);
    document.addEventListener("submit", handleSubmit);

    return () => {
      document.removeEventListener("click", handleClick, true);
      document.removeEventListener("submit", handleSubmit);
    };
  }, [ready, pathname]);

  return (
    <div
      aria-hidden="true"
      className="pointer-events-none fixed inset-x-0 top-0 z-[100] h-[2px] overflow-hidden"
    >
      <div
        className="h-full origin-left bg-[linear-gradient(90deg,rgba(159,177,0,0.78)_0%,rgba(196,214,0,0.92)_45%,rgba(228,242,91,0.78)_100%)] shadow-[0_0_8px_rgba(196,214,0,0.45)] transition-[transform,opacity] duration-300 ease-out"
        style={{
          transform: `scaleX(${progress / 100})`,
          opacity: pending || progress > 0 ? 0.92 : 0,
        }}
      />
    </div>
  );
}
