{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}

<script data-id="nodedc-auth-favicon">
    "use strict";

    (function () {
        const faviconHref = "data:image/svg+xml,%3Csvg%20width%3D%2232%22%20height%3D%2232%22%20viewBox%3D%220%200%2032%2032%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Cstyle%3E%0A%20%20%20%20.icon-fav-01%20%7B%20fill%3A%20%23333334%3B%20%7D%0A%20%20%20%20%40media%20(prefers-color-scheme%3A%20dark)%20%7B%20.icon-fav-01%20%7B%20fill%3A%20%23FEFEFE%3B%20%7D%20%7D%0A%20%20%20%20%40media%20(prefers-color-scheme%3A%20light)%20%7B%20.icon-fav-01%20%7B%20fill%3A%20%23000000%3B%20%7D%20%7D%0A%20%20%3C%2Fstyle%3E%0A%20%20%3Cpath%20class%3D%22icon-fav-01%22%20d%3D%22M17.8738%2015.9159L16.0002%2018.9718L14.1267%2015.9159H17.8738ZM23.6307%2012.7864H8.36914L15.9999%2025.2308L23.6307%2012.7864Z%22%2F%3E%0A%20%20%3Cpath%20class%3D%22icon-fav-01%22%20d%3D%22M10.9793%2019.4872L6.67269%2011.5918H25.5344L21.2281%2019.4872H25.0581L31.2614%208H0.738281L7.16244%2019.4872H10.9793Z%22%2F%3E%0A%3C%2Fsvg%3E";
        const applyFavicon = () => {
            if (!document.head) return;
            document.querySelectorAll('link[rel~="icon"]').forEach((node) => node.remove());
            const link = document.createElement("link");
            link.rel = "icon";
            link.type = "image/svg+xml";
            link.sizes = "any";
            link.href = faviconHref;
            document.head.appendChild(link);
        };
        applyFavicon();
        window.addEventListener("DOMContentLoaded", applyFavicon, { once: true });
    })();
</script>

{% with request_host=request.get_host %}
{% if request_host|slice:":11" != "auth-admin." and request_host|slice:":9" != "id-admin." and request_host|slice:":12" != "172.22.0.222" %}
{% if request.path|slice:":9" == "/if/flow/" or request.path|slice:":7" == "/flows/" or request.path|slice:":7" == "/login/" %}
<script data-id="nodedc-auth-flow-scope">
    "use strict";

    (function () {
        const isAuthentikAdminHost =
            window.location.hostname.startsWith("auth-admin.") ||
            window.location.hostname.startsWith("id-admin.") ||
            window.location.hostname === "172.22.0.222";
        const isAuthExperiencePage =
            !isAuthentikAdminHost &&
            (
                window.location.pathname.includes("/if/flow/") ||
                window.location.pathname.includes("/flows/") ||
                window.location.pathname.includes("/login/")
            );
        document.documentElement.classList.toggle("nodedc-auth-flow-page", isAuthExperiencePage);

        window.addEventListener("DOMContentLoaded", function () {
            document.body?.classList.toggle("nodedc-auth-flow-page", isAuthExperiencePage);
        }, { once: true });
    })();
</script>

<style data-id="nodedc-auth-login-css">
{% include "branding/nodedc-login.css" %}
</style>

<style data-id="nodedc-auth-critical-loader">
    html.nodedc-auth-flow-page {
        --ak-global--primary: rgb(195, 255, 102) !important;
        --ak-global--background: #0e0f10 !important;
        --ak-global--background-image: none !important;
        --pf-global--primary-color--100: rgb(195, 255, 102) !important;
        --pf-v5-global--primary-color--100: rgb(195, 255, 102) !important;
        --pf-v6-global--primary-color--100: rgb(195, 255, 102) !important;
        --pf-v4-global--palette--blue-300: rgb(195, 255, 102) !important;
        --ak-global--palette--blue-300: rgb(195, 255, 102) !important;
        --pf-global--active-color--100: rgb(195, 255, 102) !important;
        --pf-global--link--Color: rgb(195, 255, 102) !important;
        --nodedc-auth-primary: rgb(195, 255, 102) !important;
        --nodedc-auth-bg: #0e0f10 !important;
    }

    html.nodedc-auth-flow-page,
    html.nodedc-auth-flow-page body,
    html.nodedc-auth-flow-page body .pf-c-login {
        background: #0e0f10 !important;
        color-scheme: dark !important;
    }

    html.nodedc-auth-flow-page body ak-flow-executor::part(main),
    html.nodedc-auth-flow-page body .pf-c-login__main,
    html.nodedc-auth-flow-page body .pf-c-empty-state,
    html.nodedc-auth-flow-page body .pf-v5-c-empty-state,
    html.nodedc-auth-flow-page body .pf-v6-c-empty-state,
    html.nodedc-auth-flow-page body .pf-c-card,
    html.nodedc-auth-flow-page body .pf-v5-c-card,
    html.nodedc-auth-flow-page body .pf-v6-c-card,
    html.nodedc-auth-flow-page body [class*="empty-state"] {
        background: transparent !important;
        box-shadow: none !important;
        border: 0 !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
    }

    html.nodedc-auth-flow-page body .pf-c-spinner,
    html.nodedc-auth-flow-page body .pf-v5-c-spinner,
    html.nodedc-auth-flow-page body .pf-v6-c-spinner,
    html.nodedc-auth-flow-page body [role="progressbar"],
    html.nodedc-auth-flow-page body ak-spinner {
        --pf-c-spinner--Color: rgb(195, 255, 102) !important;
        --pf-v5-c-spinner--Color: rgb(195, 255, 102) !important;
        --pf-v6-c-spinner--Color: rgb(195, 255, 102) !important;
        --pf-c-spinner__clipper--after--BoxShadowColor: rgb(195, 255, 102) !important;
        --pf-c-spinner__lead-ball--after--BackgroundColor: rgb(195, 255, 102) !important;
        --pf-c-spinner__tail-ball--after--BackgroundColor: rgb(195, 255, 102) !important;
        color: rgb(195, 255, 102) !important;
    }

    html.nodedc-auth-flow-page body #ak-placeholder.ak-c-placeholder,
    html.nodedc-auth-flow-page body .ak-c-placeholder[slot="placeholder"] {
        position: fixed !important;
        top: 50% !important;
        left: 50% !important;
        display: block !important;
        width: 2.5rem !important;
        height: 2.5rem !important;
        min-width: 2.5rem !important;
        min-height: 2.5rem !important;
        margin: 0 !important;
        padding: 0 !important;
        border: 0 !important;
        border-radius: 999px !important;
        background: transparent !important;
        box-shadow: none !important;
        opacity: 1 !important;
        visibility: visible !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        transform: translate(-50%, -50%) !important;
        overflow: visible !important;
    }

    html.nodedc-auth-flow-page body #ak-placeholder.ak-c-placeholder .pf-c-spinner,
    html.nodedc-auth-flow-page body .ak-c-placeholder[slot="placeholder"] .pf-c-spinner,
    html.nodedc-auth-flow-page body #ak-placeholder.ak-c-placeholder [role="progressbar"],
    html.nodedc-auth-flow-page body .ak-c-placeholder[slot="placeholder"] [role="progressbar"] {
        opacity: 0 !important;
        visibility: hidden !important;
    }

    html.nodedc-auth-flow-page body #ak-placeholder.ak-c-placeholder::before,
    html.nodedc-auth-flow-page body .ak-c-placeholder[slot="placeholder"]::before {
        content: "";
        position: absolute;
        inset: 0;
        border: 2px solid rgba(195, 255, 102, 0.22);
        border-top-color: rgb(195, 255, 102);
        border-radius: 999px;
        animation: nodedc-auth-placeholder-spin 0.72s linear infinite;
        pointer-events: none;
    }

    html.nodedc-auth-flow-page body.nodedc-auth-loading ak-flow-executor::part(main),
    html.nodedc-auth-flow-page body.nodedc-auth-loading .pf-c-login__main {
        opacity: 0 !important;
        visibility: hidden !important;
        pointer-events: none !important;
    }

    html.nodedc-auth-flow-page body.nodedc-auth-loading::before {
        content: "";
        position: fixed;
        top: 50%;
        left: 50%;
        z-index: 1200;
        width: 2.5rem;
        height: 2.5rem;
        border: 2px solid rgba(195, 255, 102, 0.22);
        border-top-color: rgb(195, 255, 102);
        border-radius: 999px;
        transform: translate(-50%, -50%);
        animation: nodedc-auth-loader-spin 0.72s linear infinite;
        pointer-events: none;
    }

    html.nodedc-auth-flow-page body.nodedc-auth-card-ready::before {
        display: none !important;
    }

    @keyframes nodedc-auth-loader-spin {
        from {
            transform: translate(-50%, -50%) rotate(0deg);
        }

        to {
            transform: translate(-50%, -50%) rotate(360deg);
        }
    }

    @keyframes nodedc-auth-placeholder-spin {
        from {
            transform: rotate(0deg);
        }

        to {
            transform: rotate(360deg);
        }
    }
</style>
{% endif %}
{% endif %}
{% endwith %}

<script data-id="authentik-config">
    "use strict";

    const isAuthentikAdminHost =
        window.location.hostname.startsWith("auth-admin.") ||
        window.location.hostname.startsWith("id-admin.") ||
        window.location.hostname === "172.22.0.222";
    const isAuthExperiencePage =
        !isAuthentikAdminHost &&
        (
            window.location.pathname.includes("/if/flow/") ||
            window.location.pathname.includes("/flows/") ||
            window.location.pathname.includes("/login/")
        );
    const authentikBrand = JSON.parse('{{ brand_json|escapejs }}' || "{}");
    if (isAuthExperiencePage) {
        const nodedcAuthLoginCss = document.querySelector('style[data-id="nodedc-auth-login-css"]')?.textContent || "";
        authentikBrand.branding_custom_css = nodedcAuthLoginCss;
        authentikBrand.brandingCustomCss = nodedcAuthLoginCss;
    } else {
        authentikBrand.branding_custom_css = "";
        authentikBrand.brandingCustomCss = "";
    }

    window.authentik = {
        locale: "ru",
        config: JSON.parse('{{ config_json|escapejs }}' || "{}"),
        brand: authentikBrand,
        versionFamily: "{{ version_family }}",
        versionSubdomain: "{{ version_subdomain }}",
        build: "{{ build }}",
        api: {
            base: "{{ base_url }}",
            relBase: "{{ base_url_rel }}",
        },
    };
    window.addEventListener("DOMContentLoaded", function () {
        {% for message in messages %}
        window.dispatchEvent(
            new CustomEvent("ak-message", {
                bubbles: true,
                composed: true,
                detail: {
                    level: "{{ message.tags|escapejs }}",
                    message: "{{ message.message|escapejs }}",
                },
            }),
        );
        {% endfor %}
    });
</script>

{% with request_host=request.get_host %}
{% if request_host|slice:":11" != "auth-admin." and request_host|slice:":9" != "id-admin." and request_host|slice:":12" != "172.22.0.222" %}
{% if request.path|slice:":9" == "/if/flow/" or request.path|slice:":7" == "/flows/" or request.path|slice:":7" == "/login/" %}
<script data-id="nodedc-auth-field-enhancements">
    "use strict";

    (function () {
        const isAuthentikAdminHost =
            window.location.hostname.startsWith("auth-admin.") ||
            window.location.hostname.startsWith("id-admin.") ||
            window.location.hostname === "172.22.0.222";
        const isAuthExperiencePage =
            !isAuthentikAdminHost &&
            (
                window.location.pathname.includes("/if/flow/") ||
                window.location.pathname.includes("/flows/") ||
                window.location.pathname.includes("/login/")
            );
        if (!isAuthExperiencePage) return;

        document.documentElement.classList.add("nodedc-auth-flow-page");
        window.addEventListener("DOMContentLoaded", function () {
            document.body?.classList.add("nodedc-auth-flow-page");
        }, { once: true });

        const logoSvg = `
            <svg id="nodedc-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220.82 54.55" aria-hidden="true">
                <defs>
                    <style>
                        .cls-1{fill:#e2e1e1;}
                        .cls-2{fill:#dbdbdb;stroke:#dbdbdb;stroke-miterlimit:10;stroke-width:0.75px;}
                    </style>
                </defs>
                <path class="cls-1" d="M52.8,23.61,46.92,33.76,41.05,23.61H52.8m18-10.39H23.06L46.92,54.55Z"></path>
                <polygon class="cls-1" points="31.28 33.13 18.11 10.34 75.73 10.34 62.59 33.13 74.28 33.13 93.22 0 0 0 19.61 33.13 31.28 33.13"></polygon>
                <path class="cls-2" d="M116.35,18.49V1h1.27l10.34,15V1h1.33V18.49H128l-10.34-15v15Z"></path>
                <path class="cls-2" d="M140.43,18.64c-4.79,0-8.16-3.72-8.16-8.89S135.64.86,140.43.86s8.17,3.72,8.17,8.89S145.25,18.64,140.43,18.64Zm0-1.25c4,0,6.79-3.17,6.79-7.64s-2.77-7.64-6.79-7.64-6.77,3.17-6.77,7.64S136.44,17.39,140.43,17.39Z"></path>
                <path class="cls-2" d="M151.6,18.49V1h5.1c5.54,0,8.79,3.42,8.79,8.74s-3.25,8.74-8.79,8.74ZM153,17.24h3.75c4.77,0,7.42-2.92,7.42-7.49s-2.65-7.49-7.42-7.49H153Z"></path>
                <path class="cls-2" d="M168.49,1h10.77V2.26h-9.42V8.93h7.89v1.25h-7.89v7.06h9.74v1.25H168.49Z"></path>
                <path class="cls-2" d="M188.88,18.49V1H194c5.54,0,8.79,3.42,8.79,8.74s-3.25,8.74-8.79,8.74Zm1.35-1.25H194c4.77,0,7.41-2.92,7.41-7.49S198.75,2.26,194,2.26h-3.75Z"></path>
                <path class="cls-2" d="M205.15,9.75c0-5.24,3.19-8.89,8.11-8.89a6.8,6.8,0,0,1,7.1,5.52h-1.43a5.54,5.54,0,0,0-5.74-4.27c-4.05,0-6.64,3.17-6.64,7.64s2.54,7.64,6.59,7.64a5.46,5.46,0,0,0,5.74-4.29h1.43c-.75,3.52-3.4,5.54-7.15,5.54C208.27,18.64,205.15,15.05,205.15,9.75Z"></path>
            </svg>
        `;
        const clearIcon = `
            <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
                <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"></circle>
                <path d="M9 9l6 6M15 9l-6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path>
            </svg>
        `;
        const genericLoginError = "Не удалось выполнить вход. Проверьте email и пароль или запросите доступ.";
        const revokedLoginError = "Аккаунт больше не активен. Запросите доступ, если хотите подключиться снова.";
        const genericFlowErrorMessages = [
            "Response returned an error code",
            "Response returned an error",
            "Не удалось завершить операцию.",
        ];
        const accountStatusCache = new Map();
        const authTranslations = new Map([
            ["Failed to authenticate.", genericLoginError],
            ["Invalid credentials.", genericLoginError],
            ["Invalid password.", genericLoginError],
            ["Incorrect password.", genericLoginError],
            ["Authentication failed.", genericLoginError],
            ["This field is required.", "Заполните это поле."],
            ["Please enter your password", "Введите пароль"],
            ["Please enter your password.", "Введите пароль."],
            ["Please enter a valid email address.", "Введите корректную электронную почту."],
            ["Caps Lock is enabled.", "Включён Caps Lock."],
            ["Forgot username or password?", "Забыли пароль?"],
            ["Forgot password?", "Забыли пароль?"],
            ["Remember me on this device", "Запомнить на этом устройстве"],
            ["Email", "Эл. почта"],
            ["Email or Username", "Эл. почта"],
            ["Password", "Пароль"],
            ["Log in", "Войти"],
            ["Continue", "Продолжить"],
            ["Show password", "Показать пароль"],
            ["Hide password", "Скрыть пароль"],
            ["Permission denied", "Доступ запрещён"],
            ["Not you?", "Сменить пользователя"],
            ["Request has been denied.", "Доступ запрещён."],
            ["The request has been denied.", "Доступ запрещён."],
            ["В произведении запроса было отказано.", "Доступ запрещён."],
            ["Go home", "Вернуться назад"],
            ["Response returned an error code", "Не удалось завершить операцию."],
        ]);

        function visitRoots(root, callback) {
            callback(root);
            root.querySelectorAll("*").forEach((element) => {
                if (element.shadowRoot) {
                    visitRoots(element.shadowRoot, callback);
                }
            });
        }

        function ensureLogo() {
            if (!document.body || document.querySelector("[data-nodedc-auth-logo='true']")) return;

            document.body.classList.add("nodedc-auth-enhanced");
            const logo = document.createElement("a");
            logo.className = "nodedc-auth-logo";
            logo.dataset.nodedcAuthLogo = "true";
            logo.href = getLauncherBaseUrl();
            logo.setAttribute("aria-label", "NODE.DC");
            logo.innerHTML = logoSvg;
            document.body.appendChild(logo);
            updateLogoLink(logo);
        }

        function getLauncherBaseUrl() {
            const hostname = window.location.hostname;
            const launcherHostnames = {
                "id.nodedc.ru": "hub.nodedc.ru",
                "auth.nodedc.ru": "hub.nodedc.ru",
                "id.notdc.ru": "launcher.notdc.ru",
                "auth.notdc.ru": "launcher.notdc.ru",
            };
            const launcherHostname =
                launcherHostnames[hostname] ||
                (hostname.startsWith("auth.")
                    ? `launcher.${hostname.slice(5)}`
                    : hostname.startsWith("id.")
                      ? `hub.${hostname.slice(3)}`
                      : "hub.nodedc.ru");
            const port = window.location.port ? `:${window.location.port}` : "";

            return `${window.location.protocol}//${launcherHostname}${port}/`;
        }

        function updateLogoLink(logo) {
            fetch(new URL("/api/public/brand", getLauncherBaseUrl()).toString(), { cache: "no-store" })
                .then((response) => (response.ok ? response.json() : null))
                .then((payload) => {
                    if (payload?.logoLinkUrl) {
                        logo.href = payload.logoLinkUrl;
                    }
                })
                .catch(() => {});
        }

        function translateTextValue(value) {
            if (!value) return value;

            const trimmed = value.trim();
            const translated = authTranslations.get(trimmed);
            if (!translated) return value;

            return value.replace(trimmed, translated);
        }

        function translateAuthText(root) {
            const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
                acceptNode(node) {
                    const parent = node.parentElement;
                    if (!parent || !node.nodeValue?.trim()) return NodeFilter.FILTER_REJECT;
                    if (["SCRIPT", "STYLE", "SVG", "PATH", "POLYGON"].includes(parent.tagName)) {
                        return NodeFilter.FILTER_REJECT;
                    }
                    return NodeFilter.FILTER_ACCEPT;
                },
            });

            const textNodes = [];
            while (walker.nextNode()) {
                textNodes.push(walker.currentNode);
            }

            textNodes.forEach((node) => {
                const translated = translateTextValue(node.nodeValue);
                if (translated !== node.nodeValue) {
                    node.nodeValue = translated;
                }
            });

            root.querySelectorAll("[aria-label], [title], [placeholder], input[value], button").forEach((element) => {
                ["aria-label", "title", "placeholder"].forEach((attribute) => {
                    const value = element.getAttribute(attribute);
                    const translated = translateTextValue(value);
                    if (translated !== value) element.setAttribute(attribute, translated);
                });
            });
        }

        function hasPermissionDeniedScreen() {
            let denied = false;
            visitRoots(document, (root) => {
                if (denied) return;
                const text = root.textContent || "";
                denied = [
                    "Permission denied",
                    "Доступ ограничен",
                    "Доступ запрещен",
                    "Доступ запрещён",
                    "Request has been denied.",
                    "The request has been denied.",
                    "В произведении запроса было отказано.",
                    "Доступ к модулю ограничен.",
                ].some((message) => text.includes(message));
            });
            return denied;
        }

        function syncPermissionDeniedState() {
            document.body?.classList.toggle("nodedc-auth-permission-denied", hasPermissionDeniedScreen());
        }

        function findAncestor(element, predicate, maxDepth = 8) {
            let current = element;
            for (let depth = 0; current && depth < maxDepth; depth += 1) {
                if (predicate(current)) return current;
                current = current.parentElement;
            }
            return null;
        }

        function applyPermissionDeniedLayout(root) {
            const deniedTitleMessages = ["Permission denied", "Доступ ограничен", "Доступ запрещен", "Доступ запрещён"];
            const deniedSubtitle = "Доступ запрещён.";
            const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
                acceptNode(node) {
                    const text = node.nodeValue?.trim() || "";
                    return deniedTitleMessages.some((message) => text === message)
                        ? NodeFilter.FILTER_ACCEPT
                        : NodeFilter.FILTER_REJECT;
                },
            });

            const textNodes = [];
            while (walker.nextNode()) {
                textNodes.push(walker.currentNode);
            }

            textNodes.forEach((node) => {
                const titleElement = findAncestor(
                    node.parentElement,
                    (element) =>
                        element.matches?.(".pf-c-title, .pf-v5-c-title, h1, h2") ||
                        element.getAttribute?.("slot") === "title",
                );
                const header =
                    titleElement?.closest?.(".pf-c-login__main-header") ||
                    findAncestor(titleElement || node.parentElement, (element) => element.matches?.(".pf-c-login__main-header"), 10) ||
                    root.querySelector?.(".pf-c-login__main-header");

                if (titleElement) {
                    titleElement.style.display = "none";
                }
                if (header) {
                    header.setAttribute("data-nodedc-permission-denied", "true");
                    header.setAttribute("data-nodedc-denied-subtitle", deniedSubtitle);
                }
            });
        }

        function hidePermissionDeniedReason(root) {
            const deniedMessages = [
                "Request has been denied.",
                "The request has been denied.",
                "В произведении запроса было отказано.",
                "Доступ к модулю ограничен.",
                "Объяснение:",
                "Reason:",
                "Привязка политики",
                "Policy binding",
                "returned result",
                "returned a result",
                "'None' вернула результат",
            ];

            root.querySelectorAll(".pf-c-alert, .pf-v5-c-alert, .pf-c-empty-state__body, [class*='alert']").forEach((element) => {
                const text = element.textContent || "";
                if (deniedMessages.some((message) => text.includes(message))) {
                    element.style.display = "none";
                }
            });

            const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
                acceptNode(node) {
                    const text = node.nodeValue?.trim() || "";
                    return deniedMessages.some((message) => text.includes(message))
                        ? NodeFilter.FILTER_ACCEPT
                        : NodeFilter.FILTER_REJECT;
                },
            });

            const textNodes = [];
            while (walker.nextNode()) {
                textNodes.push(walker.currentNode);
            }

            textNodes.forEach((node) => {
                let element = node.parentElement;
                for (let depth = 0; element && depth < 6; depth += 1) {
                    const text = (element.textContent || "").trim();
                    if (deniedMessages.some((message) => text === message || text.endsWith(message)) && text.length <= 96) {
                        element.style.display = "none";
                        return;
                    }
                    element = element.parentElement;
                }
                if (node.parentElement) {
                    node.parentElement.style.display = "none";
                }
            });
        }

        function enhanceIdentifierField(root) {
            const input = root.querySelector("#ak-identifier-input");
            if (!input || input.dataset.nodedcClearBound === "true") return;

            const fieldGroup = input.closest(".pf-c-form__group") || input.parentElement;
            if (!fieldGroup) return;

            input.dataset.nodedcClearBound = "true";
            fieldGroup.style.position = "relative";

            const button = document.createElement("button");
            button.type = "button";
            button.tabIndex = -1;
            button.className = "nodedc-auth-clear-input";
            button.dataset.nodedcClearInput = "true";
            button.setAttribute("aria-label", "Очистить электронную почту");
            button.innerHTML = clearIcon;

            const update = () => {
                button.dataset.visible = input.value ? "true" : "false";
            };

            button.addEventListener("click", (event) => {
                event.preventDefault();
                input.value = "";
                input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
                input.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
                input.focus();
                update();
            });

            input.addEventListener("input", update);
            input.addEventListener("change", update);
            fieldGroup.appendChild(button);
            update();
        }

        function maskPasswordInput(input) {
            if (!input || input.type !== "text") return;

            input.type = "password";
            const button = input.closest(".pf-c-input-group")?.querySelector(".pf-c-button.pf-m-control");
            const icon = button?.querySelector("i");

            button?.setAttribute("aria-label", "Показать пароль");
            icon?.classList.remove("fa-eye-slash");
            icon?.classList.add("fa-eye");
        }

        function maskVisiblePasswords(target) {
            visitRoots(document, (root) => {
                root.querySelectorAll("#ak-stage-identification-password, #ak-stage-password-input").forEach((input) => {
                    const inputGroup = input.closest(".pf-c-input-group");
                    if (inputGroup?.contains(target)) return;
                    maskPasswordInput(input);
                });
            });
        }

        function enhancePasswordFields(root) {
            root.querySelectorAll("#ak-stage-identification-password, #ak-stage-password-input").forEach((input) => {
                if (input.placeholder !== "Введите пароль") {
                    input.placeholder = "Введите пароль";
                }

                if (input.dataset.nodedcBlurBound === "true") return;

                input.dataset.nodedcBlurBound = "true";
                input.addEventListener("blur", () => {
                    window.setTimeout(() => {
                        const inputGroup = input.closest(".pf-c-input-group");
                        if (inputGroup?.contains(document.activeElement)) return;
                        maskPasswordInput(input);
                    }, 0);
                });
            });
        }

        function normalizePasswordFields(root) {
            enhancePasswordFields(root);
        }

        function dispatchSyntheticInput(input) {
            if (!input) return;

            try {
                input.dispatchEvent(new InputEvent("input", {
                    bubbles: true,
                    composed: true,
                    inputType: "insertReplacementText",
                    data: input.value || "",
                }));
            } catch {
                input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
            }
            input.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
        }

        function syncFormFieldsBeforeSubmit(form) {
            form.querySelectorAll("#ak-identifier-input, #ak-stage-identification-password, #ak-stage-password-input").forEach((input) => {
                dispatchSyntheticInput(input);
            });
        }

        function enhanceSubmitHandoff(root) {
            root.querySelectorAll("form").forEach((form) => {
                if (form.dataset.nodedcSubmitBound === "true") return;

                form.dataset.nodedcSubmitBound = "true";
                form.addEventListener("submit", () => {
                    syncFormFieldsBeforeSubmit(form);
                    document.body?.classList.add("nodedc-auth-submitting");
                }, true);
            });
        }

        function ensureAccessRequestLink(root) {
            const input = root.querySelector("#ak-identifier-input, #ak-stage-identification-password, #ak-stage-password-input");
            const form = input?.closest("form") || root.querySelector("form");
            if (!input || !form || form.querySelector("[data-nodedc-access-request='true']")) return;

            const link = document.createElement("a");
            link.className = "nodedc-auth-request-access";
            link.dataset.nodedcAccessRequest = "true";
            link.href = new URL("/request-access", getLauncherBaseUrl()).toString();
            link.textContent = "Запросить доступ";
            form.appendChild(link);
        }

        function normalizeEmail(value) {
            return typeof value === "string" ? value.trim().toLowerCase() : "";
        }

        function getLoginEmail(root) {
            return normalizeEmail(root.querySelector("#ak-identifier-input")?.value);
        }

        function getLoginErrorMessages() {
            return [
                "Failed to authenticate.",
                "Invalid credentials.",
                "Invalid password.",
                "Incorrect password.",
                "Authentication failed.",
                "Не удалось выполнить вход.",
                "Неверная почта или пароль.",
                "Неверный пароль.",
                genericLoginError,
                revokedLoginError,
            ];
        }

        function replaceLoginErrorText(root, message) {
            const errorMessages = getLoginErrorMessages();
            const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
                acceptNode(node) {
                    const text = node.nodeValue?.trim() || "";
                    return errorMessages.some((errorMessage) => text.includes(errorMessage))
                        ? NodeFilter.FILTER_ACCEPT
                        : NodeFilter.FILTER_REJECT;
                },
            });
            const textNodes = [];

            while (walker.nextNode()) {
                textNodes.push(walker.currentNode);
            }

            textNodes.forEach((node) => {
                const currentValue = node.nodeValue || "";
                const trimmed = currentValue.trim();
                if (!trimmed) return;
                node.nodeValue = currentValue.replace(trimmed, message);
            });
        }

        function syncLoginErrorReason(root) {
            if (!hasAuthError(root)) return;

            replaceLoginErrorText(root, genericLoginError);
            const email = getLoginEmail(root);
            if (!email) return;

            const cachedStatus = accountStatusCache.get(email);
            if (cachedStatus === "revoked") {
                replaceLoginErrorText(root, revokedLoginError);
                return;
            }

            if (cachedStatus === "unknown" || cachedStatus === "loading") return;

            accountStatusCache.set(email, "loading");
            const statusUrl = new URL("/api/public/login-account-status", getLauncherBaseUrl());
            statusUrl.searchParams.set("email", email);

            fetch(statusUrl.toString(), { cache: "no-store" })
                .then((response) => (response.ok ? response.json() : null))
                .then((payload) => {
                    const status = payload?.status === "revoked" ? "revoked" : "unknown";
                    accountStatusCache.set(email, status);
                    if (status !== "revoked") return;
                    visitRoots(document, (candidateRoot) => {
                        replaceLoginErrorText(candidateRoot, revokedLoginError);
                    });
                })
                .catch(() => {
                    accountStatusCache.set(email, "unknown");
                });
        }

        function hasAuthError(root) {
            const hasErrorElement = root.querySelector(
                ".pf-c-alert, .pf-m-error, .pf-c-helper-text__item.pf-m-error, [aria-invalid='true']"
            );
            if (hasErrorElement) return true;

            const text = root.textContent || "";
            return getLoginErrorMessages().some((message) => text.includes(message));
        }

        function hasGenericFlowError(root) {
            const text = root.textContent || "";
            return genericFlowErrorMessages.some((message) => text.includes(message));
        }

        function hasLoadingOnlyScreen(root) {
            const isFlowExecutorRoot = root.host?.tagName?.toLowerCase() === "ak-flow-executor";
            const hasProgress =
                root.querySelector?.(".pf-c-spinner, .pf-v5-c-spinner, [role='progressbar'], ak-spinner");
            const isEmptyFlowExecutor = isFlowExecutorRoot && (root.textContent || "").trim() === "";
            const hasInteractiveAuth =
                root.querySelector?.("input, textarea, select, button[type='submit'], .pf-c-alert, .pf-v5-c-alert") ||
                hasGenericFlowError(root);

            return Boolean((hasProgress || isEmptyFlowExecutor) && !hasInteractiveAuth);
        }

        function syncLoadingState() {
            let isLoadingOnly = false;
            let hasAuthContent = false;
            visitRoots(document, (root) => {
                if (hasLoadingOnlyScreen(root)) {
                    isLoadingOnly = true;
                }
                if (
                    root.querySelector?.("input, textarea, select, button[type='submit'], .pf-c-alert, .pf-v5-c-alert") ||
                    hasGenericFlowError(root)
                ) {
                    hasAuthContent = true;
                }
            });
            const shouldShowLoader = isLoadingOnly && !hasAuthContent;

            document.body?.classList.toggle("nodedc-auth-loading", shouldShowLoader);
            document.body?.classList.toggle("nodedc-auth-card-ready", hasAuthContent);
        }

        function restoreCardOnErrors(root) {
            if (hasAuthError(root)) {
                document.body?.classList.remove("nodedc-auth-submitting");
            }
        }

        function isOidcLogoutFlow() {
            const path = window.location.pathname;
            const params = new URLSearchParams(window.location.search);

            return (
                path.includes("/end-session/") ||
                path.includes("/if/flow/default-invalidation-flow") ||
                params.has("post_logout_redirect_uri")
            );
        }

        function getSafePostLogoutRedirect() {
            const rawUrl = new URLSearchParams(window.location.search).get("post_logout_redirect_uri");
            if (!rawUrl) return null;

            try {
                const url = new URL(rawUrl);
                const allowedHosts = new Set([
                    "hub.nodedc.ru",
                    "hub.notdc.ru",
                    "launcher.notdc.ru",
                    "platform.notdc.ru",
                    "notdc.ru",
                ]);

                if (!["http:", "https:"].includes(url.protocol)) return null;
                if (!allowedHosts.has(url.hostname)) return null;
                if (!url.pathname.startsWith("/auth/logged-out")) return null;

                return url.toString();
            } catch {
                return null;
            }
        }

        function buildLoggedOutRedirectUrl() {
            return new URL("/auth/logged-out", getLauncherBaseUrl()).toString();
        }

        function redirectGenericFlowError(root) {
            if (document.body?.dataset.nodedcFlowErrorRedirected === "true") return;
            if (!window.location.pathname.includes("/if/flow/")) return;
            if (!hasGenericFlowError(root)) return;

            document.body.dataset.nodedcFlowErrorRedirected = "true";
            document.body.classList.add("nodedc-auth-submitting");
            window.setTimeout(() => {
                window.location.replace(getSafePostLogoutRedirect() || buildLoggedOutRedirectUrl());
            }, 120);
        }

        function redirectCompletedLogout(root) {
            if (!isOidcLogoutFlow() || document.body?.dataset.nodedcLogoutRedirected === "true") return;

            const redirectUrl = getSafePostLogoutRedirect();
            if (!redirectUrl) return;

            const isInvalidationFlow = window.location.pathname.includes("/if/flow/default-invalidation-flow");
            const text = root.textContent || "";
            const logoutComplete = [
                "Logout successful",
                "You've logged out",
                "You have been logged out",
                "Logged out",
                "Вы вышли",
                "Выход выполнен",
            ].some((message) => text.includes(message));

            if (!logoutComplete && !isInvalidationFlow) return;

            document.body.dataset.nodedcLogoutRedirected = "true";
            document.body.classList.add("nodedc-auth-submitting");
            window.setTimeout(() => {
                window.location.replace(redirectUrl);
            }, isInvalidationFlow ? 1600 : 150);
        }

        let scheduled = false;

        function enhanceAuthFields() {
            scheduled = false;
            ensureLogo();
            visitRoots(document, (root) => {
                enhanceIdentifierField(root);
                normalizePasswordFields(root);
                enhanceSubmitHandoff(root);
                ensureAccessRequestLink(root);
                translateAuthText(root);
                syncLoginErrorReason(root);
                applyPermissionDeniedLayout(root);
                hidePermissionDeniedReason(root);
                restoreCardOnErrors(root);
                redirectCompletedLogout(root);
                redirectGenericFlowError(root);
            });
            syncPermissionDeniedState();
            syncLoadingState();
        }

        function scheduleEnhancement() {
            if (scheduled) return;
            scheduled = true;
            window.requestAnimationFrame(enhanceAuthFields);
        }

        window.addEventListener("DOMContentLoaded", scheduleEnhancement);
        window.addEventListener("load", scheduleEnhancement);
        document.addEventListener("pointerdown", (event) => {
            const target = event.composedPath?.()[0] || event.target;
            maskVisiblePasswords(target);
        }, true);
        window.addEventListener("blur", () => maskVisiblePasswords(null));
        new MutationObserver(scheduleEnhancement).observe(document.documentElement, {
            childList: true,
            subtree: true,
        });
    })();
</script>
{% endif %}
{% endif %}
{% endwith %}
