const FRAME_ID = 'account-auth-frame';
const FRAME_HISTORY_STATE_KEY = 'vitiThemeFrame';
const VISIT_INTENT_TTL = 2000;

let registered = false;
let nextTopVisitUrl = null;
let pendingFrameVisit = null;
let nextVisitIntent = null;

function getAuthFrame() {
    const frame = document.getElementById(FRAME_ID);

    return frame instanceof HTMLElement ? frame : null;
}

function isSameOriginUrl(url) {
    return url.origin === window.location.origin;
}

function isCurrentDocumentAnchor(url) {
    const currentUrl = new URL(window.location.href);

    return url.origin === currentUrl.origin
        && url.pathname === currentUrl.pathname
        && url.search === currentUrl.search
        && url.hash !== currentUrl.hash;
}

function getEventElement(event) {
    const target = event.target;

    return target instanceof Element ? target : null;
}

function getLinkTarget(link) {
    const frameTarget = link.closest('[data-turbo-frame]')?.getAttribute('data-turbo-frame');
    const parentFrame = link.closest('turbo-frame');

    return frameTarget === FRAME_ID || (parentFrame?.id === FRAME_ID && !frameTarget)
        ? 'frame'
        : 'top';
}

function recordClickIntent(event) {
    const element = getEventElement(event);
    const link = element?.closest('a[href]');

    if (!(link instanceof HTMLElement)) {
        nextVisitIntent = null;

        return;
    }

    const targetUrl = new URL(link.getAttribute('href'), window.location.href);
    nextVisitIntent = { recordedAt: Date.now(), target: getLinkTarget(link), url: targetUrl.href };
}

function takeVisitIntent(url) {
    if (null === nextVisitIntent) {
        return null;
    }

    const intent = Date.now() - nextVisitIntent.recordedAt <= VISIT_INTENT_TTL && nextVisitIntent.url === url.href
        ? nextVisitIntent.target
        : null;
    nextVisitIntent = null;

    return intent;
}

function getFocusedVisitIntent(url) {
    const element = document.activeElement;
    const link = element instanceof Element ? element.closest('a[href]') : null;

    if (!(link instanceof HTMLElement)) {
        return null;
    }

    return new URL(link.getAttribute('href'), window.location.href).href === url.href
        ? getLinkTarget(link)
        : null;
}

function updateHistory(url, action = 'advance') {
    const nextUrl = url.href;

    if (window.location.href === nextUrl) {
        return;
    }

    const state = { turboFrame: FRAME_ID, [FRAME_HISTORY_STATE_KEY]: FRAME_ID };

    if (action === 'replace') {
        window.history.replaceState(state, '', nextUrl);

        return;
    }

    window.history.pushState(state, '', nextUrl);
}

function loadAuthFrame(url, { updateBrowserUrl = true, action = 'advance' } = {}) {
    const frame = getAuthFrame();

    if (!frame || !isSameOriginUrl(url) || isCurrentDocumentAnchor(url)) {
        return false;
    }

    const nextUrl = url.href;

    if (updateBrowserUrl) {
        pendingFrameVisit = { action, url: nextUrl };
    } else {
        pendingFrameVisit = null;
    }

    if (frame.getAttribute('src') === nextUrl) {
        if (updateBrowserUrl) {
            updateHistory(url, action);
            pendingFrameVisit = null;
        }

        return true;
    }

    frame.setAttribute('src', nextUrl);

    return true;
}

function visitTop(url) {
    nextTopVisitUrl = url.href;

    if (window.Turbo && typeof window.Turbo.visit === 'function') {
        window.Turbo.visit(nextTopVisitUrl);

        return;
    }

    window.location.href = nextTopVisitUrl;
}

export default function registerAuthTurboFrame() {
    if (registered) {
        return;
    }

    registered = true;

    document.addEventListener('click', recordClickIntent, true);

    document.addEventListener('turbo:before-visit', (event) => {
        const targetUrl = new URL(event.detail.url, window.location.href);
        const visitIntent = takeVisitIntent(targetUrl) || getFocusedVisitIntent(targetUrl);

        if (nextTopVisitUrl === targetUrl.href) {
            nextTopVisitUrl = null;

            return;
        }

        if (visitIntent === 'top') {
            return;
        }

        if (!loadAuthFrame(targetUrl, { action: event.detail.action })) {
            return;
        }

        event.preventDefault();
    });

    document.addEventListener('turbo:frame-missing', (event) => {
        if (!(event.target instanceof HTMLElement) || event.target.id !== FRAME_ID) {
            return;
        }

        pendingFrameVisit = null;
        event.preventDefault();
        visitTop(new URL(
            event.detail.response?.url || event.target.getAttribute('src') || window.location.href,
            window.location.href
        ));
    });

    document.addEventListener('turbo:frame-load', (event) => {
        if (!(event.target instanceof HTMLElement) || event.target.id !== FRAME_ID || null === pendingFrameVisit) {
            return;
        }

        if (event.target.getAttribute('src') !== pendingFrameVisit.url) {
            return;
        }

        updateHistory(new URL(pendingFrameVisit.url), pendingFrameVisit.action);
        pendingFrameVisit = null;
    });

    window.addEventListener('popstate', () => {
        loadAuthFrame(new URL(window.location.href), { updateBrowserUrl: false });
    });
}
