import UriInputField from '@/mdx-components/UriInputField';
import Tabs from '@mdx/components/Tabs';
import TabItem from '@mdx/components/TabItem';
import InlineNotification from '@/ds-components/InlineNotification';
import { generateStandardSecret } from '@logto/shared/universal';
import Steps from '@/mdx-components/Steps';
import Step from '@/mdx-components/Step';

<Steps>

<Step
  title="Add Logto SDK as a dependency"
  subtitle="Please select your favorite package manager"
>
<Tabs>
<TabItem value="npm" label="npm">

```bash
npm i @logto/next
```

</TabItem>
<TabItem value="yarn" label="Yarn">

```bash
yarn add @logto/next
```

</TabItem>
<TabItem value="pnpm" label="pnpm">

```bash
pnpm add @logto/next
```

</TabItem>
</Tabs>
</Step>

<Step
  title="Init LogtoClient"
  subtitle="1 step"
>

<InlineNotification>
  In the following steps, we assume your app is running on <code>http://localhost:3000</code>.
</InlineNotification>

Import and initialize LogtoClient:

<pre>
  <code className="language-ts">
    {`// libraries/logto.js
import LogtoClient from '@logto/next/edge';

export const logtoClient = new LogtoClient({
  endpoint: '${props.endpoint}',
  appId: '${props.app.id}',
  appSecret: '${props.app.secret}',
  baseUrl: 'http://localhost:3000', // Change to your own base URL
  cookieSecret: '${generateStandardSecret()}', // Auto-generated 32 digit secret
  cookieSecure: process.env.NODE_ENV === 'production',
});`}
  </code>
</pre>

</Step>

<Step
  title="Sign in"
  subtitle="3 steps, 4 API routes"
>

### Configure Redirect URI

First, let’s enter your redirect URI. E.g. `http://localhost:3000/api/logto/sign-in-callback`.

<UriInputField name="redirectUris" />

### Prepare API routes

Prepare [API routes](https://nextjs.org/docs/api-routes/introduction) to connect with Logto.

Go back to your IDE/editor, use the following code to implement the API routes first:

```ts
// app/api/logto/sign-in/route.ts
import { type NextRequest } from 'next/server';

import { logtoClient } from '../../../../libraries/logto';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  return logtoClient.handleSignIn()(request);
}
```

```ts
// app/api/logto/sign-in-callback/route.ts
import { type NextRequest } from 'next/server';

import { logtoClient } from '../../../../libraries/logto';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  return logtoClient.handleSignInCallback()(request);
}
```

```ts
// app/api/logto/sign-out/route.ts
import { type NextRequest } from 'next/server';

import { logtoClient } from '../../../../libraries/logto';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  return logtoClient.handleSignOut()(request);
}
```

```ts
// app/api/logto/user/route.ts
import { type NextRequest } from 'next/server';

import { logtoClient } from '../../../../libraries/logto';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  return logtoClient.handleUser()(request);
}
```

This will create 4 routes automatically:

1. `/api/logto/sign-in`: Sign in with Logto.
2. `/api/logto/sign-in-callback`: Handle sign-in callback.
3. `/api/logto/sign-out`: Sign out with Logto.
4. `/api/logto/user`: Check if user is authenticated with Logto, if yes, return user info.

### Implement sign-in button

We're almost there! In the last step, we will create a sign-in button:

```tsx
import { useRouter } from 'next/router';

const { push } = useRouter();

<button onClick={() => push('/api/logto/sign-in')}>Sign In</button>;
```

Now you will be navigated to Logto sign-in page when you click the button.

</Step>

<Step
  title="Get user profile"
  subtitle="2 steps"
>

We'll use "async component" to get user profile, check the [Data Fetching](https://nextjs.org/docs/app/building-your-application/data-fetching) doc to learn more.

### Create `getUser` helper

```tsx
// app/api/logto/user/get-user.ts
import { type LogtoContext } from '@logto/next';
import { cookies } from 'next/headers';

// `server-only` guarantees any modules that import code in file
// will never run on the client. Even though this particular api
// doesn't currently use sensitive environment variables, it's
// good practise to add `server-only` preemptively.
// eslint-disable-next-line import/no-unassigned-import
import 'server-only';
import { config } from '../../../../libraries/config';

export async function getUser() {
  const response = await fetch(`${config.baseUrl}/api/logto/user`, {
    cache: 'no-store',
    headers: {
      cookie: cookies().toString(),
    },
  });

  if (!response.ok) {
    throw new Error('Something went wrong!');
  }

  // eslint-disable-next-line no-restricted-syntax
  const user = (await response.json()) as LogtoContext;

  return user;
}
```

### Create an async component to fetch

```tsx
import { getUser } from './api/logto/user/get-user';

const Page = async () => {
  const user = await getUser();

  console.log(user); // You'll get user profile here.

  return (
    <div>
      <header>
        <h1>Hello Logto.</h1>
      </header>
    </div>
  );
};

export default Page;
```

</Step>

<Step
  title="Protect API resources"
>

Call `logtoClient.getLogtoContext` to get user authentication state.

```ts
// pages/api/protected-resource.ts
import { type NextRequest } from 'next/server';

import { logtoClient } from '../../../../libraries/logto-edge';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  const { isAuthenticated, scopes } = await logtoClient.getLogtoContext(request);

  if (!isAuthenticated) {
    return new Response(JSON.stringify({ message: 'Unauthorized' }), { status: 401 });
  }

  return new Response(
    JSON.stringify({
      data: 'this_is_protected_resource',
    })
  );
}
```

</Step>

<Step
  title="Sign out"
  subtitle="1 step"
>

Calling `/api/logto/sign-out` will clear all the Logto data in memory and cookies if they exist.

After signing out, it'll be great to redirect user back to your website. Let's add `http://localhost:3000` as the Post Sign-out URI below before calling `/api/logto/sign-out`.

<UriInputField name="postLogoutRedirectUris" />

### Implement a sign-out button

```tsx
<button onClick={() => push('/api/logto/sign-out')}>Sign Out</button>
```

</Step>

</Steps>
