<!-- #region ProtectedRoute [C:3] [TYPE Component] [SEMANTICS auth, route-guard, permission, session, redirect] -->
<!-- @BRIEF Component component: components/auth/ProtectedRoute.svelte -->
<!-- @LAYER UI -->
<!--
@SEMANTICS: auth, route-guard, permission, redirect, session-validation
@PURPOSE: Enforces authenticated and authorized access before protected route content is rendered.
@LAYER UI
@RELATION BINDS_TO ->[EXT:frontend:authStore]
@RELATION CALLS ->[EXT:frontend:goto]
@RELATION DEPENDS_ON ->[PermissionsModule]
@RELATION CALLS ->[EXT:frontend:fetchApi]
@INVARIANT: Unauthenticated users are redirected to /login, unauthorized users are redirected to fallbackPath, and protected slot renders only when access is verified.
@UX_STATE: Idle -> Component mounted, verification not yet started.
@UX_STATE: Loading -> Spinner is rendered while auth/session/permission validation is in progress.
@UX_STATE: Error -> Session validation failure triggers logout and /login redirect.
@UX_STATE: Success -> Protected slot content is rendered for authenticated users with valid access.
@UX_FEEDBACK: Spinner feedback during Loading and navigation redirect feedback on Error/Unauthorized outcomes.
@UX_RECOVERY: Re-authenticate via /login after logout; retry occurs automatically on next protected navigation.
@UX_REACTIVITY: Props are bound via $props; local mutable UI flags use $state; auth store is consumed through Svelte store subscription ($auth).
@TEST_CONTRACT: [token:user:requiredPermission] -> [redirect:/login | redirect:fallbackPath | render:slot]
@TEST_SCENARIO: MissingTokenRedirect -> Navigates to /login and suppresses slot render.
@TEST_SCENARIO: PermissionDeniedRedirect -> Navigates to fallbackPath and suppresses slot render.
@TEST_SCENARIO: AuthorizedRender -> Renders slot when authenticated and permission passes.
@TEST_FIXTURE: AuthGuardStateMatrix -> INLINE_JSON
@TEST_EDGE: missing_field -> user payload missing in store triggers /auth/me fetch, then logout+redirect on failure.
@TEST_EDGE: invalid_type -> requiredPermission malformed (non-string/null) resolves to denied path and fallback redirect.
@TEST_EDGE: external_fail -> /auth/me network/API failure triggers logout and /login redirect.
@TEST_INVARIANT: GuardRedirectPolicy -> VERIFIED_BY: [MissingTokenRedirect, PermissionDeniedRedirect]
@TEST_INVARIANT: ProtectedRenderGate -> VERIFIED_BY: [AuthorizedRender]
-->

<!-- @INVARIANT All routes except login gated behind authenticated session and RBAC check. -->
<!--
@PURPOSE: Wraps protected slot content with session and permission verification guards.
@PRE: auth store and navigation API are available in runtime; component is mounted in a browser context.
@POST: Slot renders only when $auth.isAuthenticated and hasRouteAccess are both true.
@SIDE_EFFECT: Performs /auth/me request, mutates auth store state, emits console instrumentation logs, and executes navigation redirects.
@DATA_CONTRACT: Input[$props.requiredPermission?: string|null, $props.fallbackPath?: string] -> Output[UIState{isCheckingAccess:boolean, hasRouteAccess:boolean}]
-->

<script lang="ts">
    import { onMount } from "svelte";
    import { auth } from "../../lib/auth/store.svelte.js";
    import { api } from "../../lib/api";
    import { goto } from "$app/navigation";
    import { ROUTES } from "$lib/routes";
    import { hasPermission } from "$lib/auth/permissions.js";

    const { requiredPermission = null, fallbackPath = "/profile", children } = $props();

    let hasRouteAccess = $state(false);
    let isCheckingAccess = $state(true);

    const belief_scope = async (scopeId, run) => {
        console.info(`[${scopeId}][REASON] belief_scope.enter`);
        try {
            return await run();
        } finally {
            console.info(`[${scopeId}][REFLECT] belief_scope.exit`);
        }
    };

    // #region verifySessionAndAccess:Function [TYPE Function]
    /**
     * @PURPOSE: Validates session and optional permission gate before allowing protected content render.
     * @PRE: auth store is initialized and can provide token/user state; navigation is available.
     * @POST: hasRouteAccess=true only when user identity is valid and permission check (if provided) passes.
     * @SIDE_EFFECT: Mutates auth loading/user state, performs API I/O to /auth/me, and may redirect.
     * @DATA_CONTRACT: Input[AuthState, requiredPermission, fallbackPath] -> Output[RouteDecision{login_redirect|fallback_redirect|grant}]
     */
    async function verifySessionAndAccess() {
        return belief_scope("ProtectedRoute.verifySessionAndAccess", async () => {
            console.info("[ProtectedRoute.verifySessionAndAccess][REASON] Starting route access verification");
            isCheckingAccess = true;

            try {
                if (!$auth.token) {
                    auth.setLoading(false);
                    console.info("[ProtectedRoute.verifySessionAndAccess][REFLECT] Missing token, redirecting to /login");
                    await goto(ROUTES.login());
                    return;
                }

                let currentUser = $auth.user;
                if (!currentUser) {
                    auth.setLoading(true);
                    try {
                        const user = await api.fetchApi("/auth/me");
                        auth.setUser(user);
                        currentUser = user;
                        console.info("[ProtectedRoute.verifySessionAndAccess][REASON] Session user hydrated from /auth/me");
                    } catch (error) {
                        console.warn("[ProtectedRoute.verifySessionAndAccess][EXPLORE] Session validation failed", { error });
                        auth.logout();
                    await goto(ROUTES.login());
                    return;
                    } finally {
                        auth.setLoading(false);
                    }
                }

                if (!currentUser) {
                    auth.logout();
                    console.info("[ProtectedRoute.verifySessionAndAccess][REFLECT] User unresolved, redirecting to /login");
                    await goto(ROUTES.login());
                    return;
                }

                if (requiredPermission && !hasPermission(currentUser, requiredPermission, "READ")) {
                    console.info("[ProtectedRoute.verifySessionAndAccess][REFLECT] Permission denied, redirecting to fallback", {
                        requiredPermission,
                        fallbackPath,
                    });
                    hasRouteAccess = false;
                    await goto(fallbackPath);
                    return;
                }

                hasRouteAccess = true;
                console.info("[ProtectedRoute.verifySessionAndAccess][REFLECT] Access granted");
            } finally {
                isCheckingAccess = false;
                console.info("[ProtectedRoute.verifySessionAndAccess][REFLECT] Verification cycle completed", {
                    isCheckingAccess,
                    hasRouteAccess,
                });
            }
        });
    }
    // #endregion verifySessionAndAccess:Function

    onMount(() => {
        void verifySessionAndAccess();
    });
</script>

{#if $auth.loading || isCheckingAccess}
    <div class="flex items-center justify-center min-h-screen">
        <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-ring"></div>
    </div>
{:else if $auth.isAuthenticated && hasRouteAccess}
    {@render children?.()}
{/if}

<!-- #endregion ProtectedRoute -->
