"use client";

import { usePathname, useSearchParams } from "next/navigation";
import { useEffect, useRef, useState } from "react";
import { ROUTE_PROGRESS_START_EVENT } from "@/utils/routeProgress";

const MAX_LOADING_MS = 8000;

function isInternalNavigationClick(e: MouseEvent) {
    if (e.defaultPrevented || e.button !== 0) return false;
    if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return false;

    const anchor = (e.target as HTMLElement)?.closest?.("a");
    if (!anchor || !(anchor instanceof HTMLAnchorElement)) return false;
    if (anchor.target && anchor.target !== "_self") return false;
    if (anchor.hasAttribute("download")) return false;

    const href = anchor.getAttribute("href");
    if (!href || href.startsWith("#") || href.startsWith("mailto:") || href.startsWith("tel:")) return false;

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

    return true;
}

export default function RouteProgressBar() {
    const [progress, setProgress] = useState(0);
    const [visible, setVisible] = useState(false);
    const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
    const safetyTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
    const pathname = usePathname();
    const searchParams = useSearchParams();

    const start = () => {
        if (intervalRef.current) return;

        setVisible(true);
        setProgress(10);

        intervalRef.current = setInterval(() => {
            setProgress((prev) => (prev >= 85 ? prev : prev + (85 - prev) * 0.1));
        }, 200);

        if (safetyTimeoutRef.current) clearTimeout(safetyTimeoutRef.current);
        safetyTimeoutRef.current = setTimeout(finish, MAX_LOADING_MS);
    };

    const finish = () => {
        if (intervalRef.current) {
            clearInterval(intervalRef.current);
            intervalRef.current = null;
        }
        if (safetyTimeoutRef.current) {
            clearTimeout(safetyTimeoutRef.current);
            safetyTimeoutRef.current = null;
        }

        setProgress(100);
        setTimeout(() => {
            setVisible(false);
            setProgress(0);
        }, 250);
    };

    useEffect(() => {
        const onStart = () => start();
        const onClick = (e: MouseEvent) => {
            if (isInternalNavigationClick(e)) start();
        };

        window.addEventListener(ROUTE_PROGRESS_START_EVENT, onStart);
        document.addEventListener("click", onClick, true);

        return () => {
            window.removeEventListener(ROUTE_PROGRESS_START_EVENT, onStart);
            document.removeEventListener("click", onClick, true);
            if (intervalRef.current) clearInterval(intervalRef.current);
            if (safetyTimeoutRef.current) clearTimeout(safetyTimeoutRef.current);
        };
    }, []);

    useEffect(() => {
        if (intervalRef.current) finish();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [pathname, searchParams]);

    if (!visible) return null;

    return (
        <div
            className="fixed top-0 left-0 right-0 z-100 h-0.75 bg-transparent pointer-events-none"
            aria-hidden="true"
        >
            <div
                className="h-full bg-primary-500 shadow-[0_0_8px_var(--color-primary-500)] transition-[width] duration-200 ease-out"
                style={{ width: `${progress}%` }}
            />
        </div>
    );
}
