/**
 * Next.js Auth0 React Hooks & Protection Middleware
 *
 * nextjs-auth0互換のHooksとミドルウェア:
 * - useUser() - ユーザー情報取得フック
 * - UserProvider - Reactコンテキストプロバイダー
 * - withApiAuthRequired() - API保護ミドルウェア
 * - withPageAuthRequired() - ページ保護ミドルウェア
 */
'use client';
import React, { createContext, useContext, useEffect, useState } from 'react';
/**
 * User Context
 */
const UserContext = createContext(undefined);
/**
 * 🎣 UserProvider - Reactコンテキストプロバイダー
 */
export function UserProvider({ children, user: initialUser, profileUrl = '/auth/profile', loginUrl = '/auth/login' }) {
    const [user, setUser] = useState(initialUser || null);
    const [error, setError] = useState();
    const [isLoading, setIsLoading] = useState(!initialUser);
    /**
     * セッション確認
     */
    const checkSession = async () => {
        try {
            setIsLoading(true);
            setError(undefined);
            const response = await fetch(profileUrl, {
                credentials: 'same-origin',
            });
            if (response.ok) {
                const data = await response.json();
                setUser(data.user);
            }
            else if (response.status === 401) {
                setUser(null);
            }
            else {
                throw new Error(`Failed to fetch user: ${response.status}`);
            }
        }
        catch (err) {
            setError(err instanceof Error ? err : new Error('Unknown error'));
            setUser(null);
        }
        finally {
            setIsLoading(false);
        }
    };
    /**
     * 初期化時にセッション確認
     */
    useEffect(() => {
        if (!initialUser) {
            checkSession();
        }
    }, [initialUser]);
    const contextValue = {
        user,
        error,
        isLoading,
        checkSession,
    };
    return (<UserContext.Provider value={contextValue}>
      {children}
    </UserContext.Provider>);
}
/**
 * 🎣 useUser Hook - ユーザー情報取得
 */
export function useUser() {
    const context = useContext(UserContext);
    if (context === undefined) {
        throw new Error('useUser must be used within a UserProvider');
    }
    return context;
}
/**
 * 🛡️ Server-side Protection Middleware
 */
/**
 * API Route保護用のwrapper
 */
export function withApiAuthRequired(handler) {
    return async (...args) => {
        try {
            // Server-side sessionチェック
            const session = await getServerSession();
            if (!session) {
                return new Response(JSON.stringify({
                    error: 'unauthorized',
                    message: 'Authentication required'
                }), {
                    status: 401,
                    headers: { 'Content-Type': 'application/json' }
                });
            }
            // 元のハンドラーを実行
            return await handler(...args);
        }
        catch (error) {
            console.error('withApiAuthRequired error:', error);
            return new Response(JSON.stringify({
                error: 'internal_server_error',
                message: 'Internal server error'
            }), {
                status: 500,
                headers: { 'Content-Type': 'application/json' }
            });
        }
    };
}
/**
 * Page Component保護用のwrapper
 */
export function withPageAuthRequired(Component, options = {}) {
    const { loginUrl = '/auth/login' } = options;
    const ProtectedComponent = (props) => {
        const { user, isLoading, error } = useUser();
        const [isMounted, setIsMounted] = useState(false);
        useEffect(() => {
            setIsMounted(true);
        }, []);
        // Hydration対策: マウント前は統一された表示
        if (!isMounted) {
            return (<div style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    minHeight: '200px'
                }}>
          <div>Loading...</div>
        </div>);
        }
        // ローディング中
        if (isLoading) {
            return (<div style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    minHeight: '200px'
                }}>
          <div>Loading...</div>
        </div>);
        }
        // エラー発生
        if (error) {
            return (<div style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    minHeight: '200px'
                }}>
          <div>Error: {error.message}</div>
        </div>);
        }
        // 未認証の場合はリダイレクト
        if (!user) {
            const returnTo = options.returnTo || window.location.pathname;
            const redirectUrl = `${loginUrl}?returnTo=${encodeURIComponent(returnTo)}`;
            window.location.href = redirectUrl;
            return (<div style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    minHeight: '200px'
                }}>
          <div>Redirecting to login...</div>
        </div>);
        }
        // 認証済みの場合は元のコンポーネントを表示
        return <Component {...props}/>;
    };
    // Display nameを設定
    ProtectedComponent.displayName = `withPageAuthRequired(${Component.displayName || Component.name || 'Component'})`;
    return ProtectedComponent;
}
/**
 * 🔧 Server-side Utilities
 */
/**
 * サーバーサイドでセッションを取得（Server Componentで使用）
 */
async function getServerSession() {
    try {
        // Dynamic importを使用してServer-side限定の関数を呼び出し
        const { getSession } = await import('./nextjs-auth0');
        return await getSession();
    }
    catch (error) {
        console.error('Failed to get server session:', error);
        return null;
    }
}
/**
 * 🎯 Higher-Order Components (HOCs)
 */
/**
 * 認証が必要なレイアウトコンポーネント
 */
export function AuthenticatedLayout({ children, fallback }) {
    const { user, isLoading } = useUser();
    if (isLoading) {
        return fallback || (<div style={{
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                minHeight: '100vh'
            }}>
        <div>Loading...</div>
      </div>);
    }
    if (!user) {
        return (<div style={{
                display: 'flex',
                flexDirection: 'column',
                justifyContent: 'center',
                alignItems: 'center',
                minHeight: '100vh'
            }}>
        <h2>Authentication Required</h2>
        <div style={{ marginTop: '1rem' }}>
          <a href="/auth/login" style={{
                padding: '0.5rem 1rem',
                backgroundColor: '#0070f3',
                color: 'white',
                textDecoration: 'none',
                borderRadius: '4px',
                marginRight: '0.5rem'
            }}>
            Log In
          </a>
          <a href="/auth/login?screen_hint=signup" style={{
                padding: '0.5rem 1rem',
                backgroundColor: '#28a745',
                color: 'white',
                textDecoration: 'none',
                borderRadius: '4px'
            }}>
            Sign Up
          </a>
        </div>
      </div>);
    }
    return <>{children}</>;
}
/**
 * 🎛️ Utility Hooks
 */
/**
 * Access Token取得フック
 */
export function useAccessToken() {
    const [accessToken, setAccessToken] = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState(null);
    const fetchAccessToken = async () => {
        try {
            setIsLoading(true);
            setError(null);
            const response = await fetch('/auth/access-token', {
                credentials: 'same-origin',
            });
            if (response.ok) {
                const data = await response.json();
                setAccessToken(data.accessToken);
            }
            else {
                throw new Error(`Failed to fetch access token: ${response.status}`);
            }
        }
        catch (err) {
            setError(err instanceof Error ? err : new Error('Unknown error'));
        }
        finally {
            setIsLoading(false);
        }
    };
    useEffect(() => {
        fetchAccessToken();
    }, []);
    return {
        accessToken,
        isLoading,
        error,
        refetch: fetchAccessToken,
    };
}
/**
 * ログアウト機能フック
 */
export function useLogout() {
    const logout = (returnTo) => {
        const logoutUrl = returnTo
            ? `/auth/logout?returnTo=${encodeURIComponent(returnTo)}`
            : '/auth/logout';
        if (typeof window !== 'undefined') {
            window.location.href = logoutUrl;
        }
    };
    return logout;
}
/**
 * 📖 使用例
 */
export const nextjsAuth0HooksExamples = {
    /**
     * App Component での UserProvider 設定例
     */
    appComponent: `
// app/layout.tsx
import { UserProvider } from './src/nextjs-auth0-hooks';
import { getSession } from './src/nextjs-auth0';

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const session = await getSession();

  return (
    <html>
      <body>
        <UserProvider user={session?.user}>
          {children}
        </UserProvider>
      </body>
    </html>
  );
}
  `,
    /**
     * Client Component での useUser 使用例
     */
    clientComponent: `
'use client';
import { useUser, useLogout } from './src/nextjs-auth0-hooks';

export default function UserProfile() {
  const { user, isLoading, error } = useUser();
  const logout = useLogout();

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!user) return <div>Not authenticated</div>;

  return (
    <div>
      <h1>Welcome, {user.name}!</h1>
      <p>Email: {user.email}</p>
      <button onClick={() => logout()}>Logout</button>
    </div>
  );
}
  `,
    /**
     * Protected Page の実装例
     */
    protectedPage: `
'use client';
import { withPageAuthRequired } from './src/nextjs-auth0-hooks';

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <p>This page is protected and requires authentication.</p>
    </div>
  );
}

export default withPageAuthRequired(Dashboard);
  `,
    /**
     * Protected API Route の実装例
     */
    protectedApi: `
// app/api/protected/route.ts
import { withApiAuthRequired } from './src/nextjs-auth0-hooks';

async function handler() {
  return Response.json({ 
    message: 'This is a protected API route',
    timestamp: new Date().toISOString()
  });
}

export const GET = withApiAuthRequired(handler);
export const POST = withApiAuthRequired(handler);
  `,
    /**
     * Layout with Authentication の実装例
     */
    authenticatedLayout: `
'use client';
import { AuthenticatedLayout } from './src/nextjs-auth0-hooks';

export default function AppLayout({ children }: { children: React.ReactNode }) {
  return (
    <AuthenticatedLayout
      fallback={<div>Loading your dashboard...</div>}
    >
      <nav>
        <h1>My App</h1>
      </nav>
      <main>{children}</main>
    </AuthenticatedLayout>
  );
}
  `,
    /**
     * Access Token使用例
     */
    accessTokenUsage: `
'use client';
import { useAccessToken } from './src/nextjs-auth0-hooks';

export default function ApiCaller() {
  const { accessToken, isLoading, error } = useAccessToken();

  const callProtectedApi = async () => {
    if (!accessToken) return;

    const response = await fetch('/api/protected', {
      headers: {
        'Authorization': \`Bearer \${accessToken}\`
      }
    });

    const data = await response.json();
    console.log(data);
  };

  if (isLoading) return <div>Loading access token...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <button onClick={callProtectedApi}>
      Call Protected API
    </button>
  );
}
  `,
};
//# sourceMappingURL=nextjs-auth0-hooks.jsx.map