import { NextResponse, NextRequest } from 'next/server';
import { AuthTokensResponse } from '@sylphx/contract';

/**
 * Sylphx Unified Middleware — State of the Art
 *
 * ONE middleware function handles EVERYTHING:
 * - Auth routes (mounted automatically, zero manual API routes)
 * - Token refresh (automatic, every request)
 * - Route protection
 * - Cookie management
 *
 * This follows Auth0 v4 / Clerk / Supabase patterns where middleware
 * handles all auth concerns. Apps don't need to create any /api/auth/* routes.
 *
 * @example
 * ```typescript
 * // middleware.ts (or proxy.ts for Next.js 16)
 * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'
 *
 * export default createSylphxMiddleware({
 *   publicRoutes: ['/', '/about', '/pricing'],
 * })
 *
 * export const config = {
 *   matcher: ['/((?!_next|.*\\..*).*)', '/'],
 * }
 * ```
 *
 * That's it. No /api/auth/* routes needed.
 */

interface SylphxMiddlewareConfig {
    /**
     * Routes that don't require authentication.
     * Supports exact paths and wildcards.
     *
     * @example ['/', '/about', '/pricing', '/blog/*']
     * @default ['/']
     */
    publicRoutes?: string[];
    /**
     * Routes that middleware should completely ignore.
     * Use for webhooks, static assets, or third-party integrations.
     *
     * @default []
     */
    ignoredRoutes?: string[];
    /**
     * URL to redirect unauthenticated users.
     * @default '/login'
     */
    signInUrl?: string;
    /**
     * URL to redirect after sign out.
     * @default '/'
     */
    afterSignOutUrl?: string;
    /**
     * URL to redirect after successful sign in.
     * @default '/dashboard'
     */
    afterSignInUrl?: string;
    /**
     * Auth routes prefix. Routes are mounted at:
     * - {prefix}/callback — OAuth callback handler
     * - {prefix}/signout — Sign out handler
     *
     * @default '/auth'
     */
    authPrefix?: string;
    /**
     * Enable debug logging.
     * @default false
     */
    debug?: boolean;
    /**
     * Secret key for authentication.
     * Override to use a programmatic key instead of SYLPHX_SECRET_URL env var.
     *
     * Use case: Platform Console uses dynamically generated keys.
     *
     * @default credential parsed from process.env.SYLPHX_SECRET_URL
     */
    secretKey?: string;
    /**
     * Server connection URL for authentication.
     *
     * Format: sylphx://sk_<env>_<hex>@<tenant>.api.sylphx.com
     *
     * @default process.env.SYLPHX_SECRET_URL
     */
    secretUrl?: string;
    /**
     * Platform URL for API calls.
     * Override for self-hosted or same-origin deployments.
     *
     * @default resolved from SYLPHX_SECRET_URL, SYLPHX_URL, SYLPHX_BAAS_URL, or SYLPHX_RUNTIME_URL
     */
    platformUrl?: string;
    /**
     * Callback to add custom headers/logic to responses.
     * Called for every non-auth-route request after SDK processing.
     *
     * Use case: Add security headers, tracking cookies, etc.
     *
     * @example
     * ```typescript
     * onResponse: (response, request) => {
     *   response.headers.set('X-Custom-Header', 'value')
     * }
     * ```
     */
    onResponse?: (response: NextResponse, request: NextRequest) => void | Promise<void>;
    /**
     * Require authenticated requests to carry an active organization context.
     * When true, protected routes without an `org_id` JWT claim redirect to
     * `orgSelectionUrl`.
     *
     * @default false
     */
    orgRequired?: boolean;
    /**
     * URL for selecting an active organization when `orgRequired` is enabled.
     *
     * @default '/select-organization'
     */
    orgSelectionUrl?: string;
    /**
     * Active organization context behaviour.
     *
     * Enabled by default so Next.js apps get durable org-scoped sessions without
     * writing their own refresh/switch orchestration:
     * - `/auth/switch-org` records the selected org in SDK-owned HttpOnly cookies
     * - token refresh restores that org-scoped JWT when possible
     * - single-org users are auto-scoped after refresh
     *
     * Apps migrating from pre-SDK org cookies can list additional cookie names
     * for read compatibility. The SDK still writes only its own names.
     */
    organizationContext?: SylphxOrganizationContextConfig;
}
interface SylphxOrganizationContextConfig {
    /**
     * Preserve active organization context through refresh.
     * @default true
     */
    enabled?: boolean;
    /**
     * When no active org preference exists and the user has exactly one org,
     * automatically restore an org-scoped session token after refresh.
     * @default true
     */
    autoSelectSingleOrganization?: boolean;
    /**
     * Additional org-id cookie names to read during migration from existing apps.
     * The SDK-owned `__{namespace}_active_org_id` cookie is always read first.
     */
    additionalOrgIdCookies?: readonly string[];
    /**
     * Additional org-slug cookie names to read during migration from existing apps.
     * The SDK-owned `__{namespace}_active_org_slug` cookie is always read first.
     */
    additionalOrgSlugCookies?: readonly string[];
}
/**
 * Create Sylphx middleware — State of the Art
 *
 * ONE function handles everything:
 * - Auth routes ({authPrefix}/callback, {authPrefix}/signout)
 * - Token refresh (automatic, every request)
 * - Route protection
 * - Cookie management
 *
 * @example
 * ```typescript
 * // middleware.ts (or proxy.ts for Next.js 16)
 * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'
 *
 * export default createSylphxMiddleware({
 *   publicRoutes: ['/', '/about', '/pricing'],
 * })
 *
 * export const config = {
 *   matcher: ['/((?!_next|.*\\..*).*)', '/'],
 * }
 * ```
 */
declare function createSylphxMiddleware(userConfig?: SylphxMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
declare const sylphxMiddleware: typeof createSylphxMiddleware;
/**
 * Create recommended matcher config
 */
declare function createMatcher(): {
    matcher: string[];
};
/**
 * Get cookie namespace from secret key (for advanced use)
 */
declare function getNamespace(secretKey: string): string;

/**
 * Auth Functions
 *
 * Pure functions for authentication - no hidden state.
 * Each function takes config as the first parameter.
 *
 * Uses REST API at /api/sdk/auth/* for all operations.
 *
 * Types are re-exported from `@sylphx/contract` (ADR-084). The contract is
 * the single source of truth for every wire shape — this module only adds
 * SDK-specific ergonomics (User brand swap, introspection result, invite
 * envelopes, org-token claims).
 */

/**
 * Token response — contract's `AuthTokensResponse.user` (optional `AuthUser`)
 * is re-mapped to the SDK's broader `User` type so legacy callers keep the
 * familiar brand. `AuthUser` and `User` are structurally identical, but
 * the SDK surface has wider reach (cookies, middleware, React hooks) and
 * renaming is out of scope for ADR-084 cleanup.
 */
type TokenResponse = Omit<AuthTokensResponse, 'user'> & {
    user: User;
};

/**
 * SDK-specific types — cross-layer helpers and server-first configuration.
 *
 * Wire-shape types (API request/response envelopes) live in
 * `@sylphx/contract` and are re-exported per namespace from their SDK
 * module (e.g. `Plan` / `Subscription` from `./billing`, `ConsentType`
 * from `./consent`, `TokenResponse` from `./auth`). React-hook wrapper
 * shapes live in `./react/types` (tRPC-like convenience shapes that
 * are not part of the platform wire).
 *
 * History: pre-ADR-084 this file mirrored every wire shape the SDK
 * exposed; those aliases now come directly from `@sylphx/contract`.
 */

/** SDK cookie/token shape. Richer authenticated surfaces live in `./react/types` `UserProfile`. */
interface User {
    id: string;
    email: string;
    name: string | null;
    image?: string | null;
    emailVerified?: boolean;
    role?: string;
    createdAt?: string;
}
interface UserCookieData {
    user: User;
    /** Epoch ms when the session expires (client-side expiry check). */
    expiresAt: number;
}

/**
 * Server-side Auth Helpers for Next.js
 *
 * Use in Server Components and API Routes.
 *
 * Architecture: Cookie-Centric Single Source of Truth
 * ===================================================
 *
 * All auth state lives in cookies. The auth() function reads
 * from HttpOnly cookies and refreshes if needed.
 *
 * Cookie Structure:
 * - __sylphx_{namespace}_session  — HttpOnly JWT (5 min)
 * - __sylphx_{namespace}_refresh  — HttpOnly refresh token (30 days)
 * - __sylphx_{namespace}_user     — JS-readable user data (5 min)
 */

/**
 * Configure the SDK for server-side usage
 *
 * NOTE: This is optional! The SDK auto-configures from environment variables:
 * - SYLPHX_SECRET_URL
 *
 * Use this only if you need to override the default configuration.
 *
 * @example
 * ```ts
 * // Optional: Override default configuration
 * import { configureServer } from '@sylphx/sdk/nextjs'
 *
 * configureServer({
 *   secretUrl: process.env.SYLPHX_SECRET_URL!,
 * })
 * ```
 */
declare function configureServer(config: {
    secretKey?: string;
    secretUrl?: string;
    platformUrl?: string;
}): void;
/**
 * Auth state returned by auth()
 */
interface AuthResult {
    userId: string | null;
    user: User | null;
    /** Session token (for internal use only - not exposed to client) */
    sessionToken: string | null;
}
/**
 * Get the current auth state (memoized per request)
 *
 * This is the primary way to check authentication in Server Components.
 * It reads from HttpOnly cookies and refreshes if needed.
 *
 * @example
 * ```ts
 * // In a Server Component
 * import { auth } from '@sylphx/platform-sdk/nextjs'
 *
 * export default async function Dashboard() {
 *   const { userId, user } = await auth()
 *
 *   if (!userId) {
 *     redirect('/login')
 *   }
 *
 *   return <div>Hello, {user?.name}</div>
 * }
 * ```
 */
declare const auth: () => Promise<AuthResult>;
/**
 * Get the current user (null if not logged in)
 *
 * @example
 * ```ts
 * import { currentUser } from '@sylphx/platform-sdk/nextjs'
 *
 * export default async function Header() {
 *   const user = await currentUser()
 *   if (!user) return <SignIn />
 *   return <span>Hello, {user.name}</span>
 * }
 * ```
 */
declare function currentUser(): Promise<User | null>;
/**
 * Get the current user ID (null if not logged in)
 */
declare function currentUserId(): Promise<string | null>;
/**
 * Handle OAuth callback - exchange code for tokens and set cookies
 *
 * NOTE: With createSylphxMiddleware(), this is handled automatically.
 * You don't need to create manual /api/auth/* routes.
 *
 * This function is exported for advanced use cases where you need
 * custom callback handling outside of the middleware flow.
 *
 * @example
 * ```ts
 * // Using middleware (recommended - zero manual routes)
 * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'
 * export default createSylphxMiddleware({ publicRoutes: ['/', '/about'] })
 *
 * // Middleware automatically handles /auth/callback
 * ```
 */
declare function handleCallback(code: string): Promise<User>;
/**
 * Sign out - clear cookies and optionally revoke token
 *
 * NOTE: With createSylphxMiddleware(), signout is handled automatically
 * at /auth/signout. No manual route needed.
 *
 * This function is exported for advanced use cases.
 *
 * @example
 * ```ts
 * // Using middleware (recommended)
 * // Navigate users to /auth/signout - middleware handles everything
 * <a href="/auth/signout">Sign Out</a>
 * ```
 */
declare function signOut(): Promise<void>;
/**
 * Sync tokens to cookies (server action)
 *
 * NOTE: With createSylphxMiddleware(), OAuth callbacks are handled
 * automatically at /auth/callback. This function is rarely needed.
 *
 * Use only for edge cases like custom OAuth providers not going
 * through the standard flow.
 */
declare function syncAuthToCookies(tokens: TokenResponse): Promise<void>;
/**
 * Get authorization URL for OAuth redirect
 */
declare function getAuthorizationUrl(options?: {
    redirectUri?: string;
    mode?: 'login' | 'signup';
    state?: string;
    appId?: string;
}): string;
/**
 * Get the current session token for API calls
 *
 * This is for apps that need to call third-party APIs with the session token.
 * For same-origin API calls, cookies are sent automatically.
 *
 * @example
 * ```ts
 * // In an API route that needs to call external APIs
 * import { getSessionToken } from '@sylphx/platform-sdk/nextjs'
 *
 * export async function GET() {
 *   const token = await getSessionToken()
 *   if (!token) {
 *     return new Response('Unauthorized', { status: 401 })
 *   }
 *
 *   // Call third-party API
 *   const response = await fetch('https://api.example.com/data', {
 *     headers: { Authorization: `Bearer ${token}` }
 *   })
 *   // ...
 * }
 * ```
 */
declare function getSessionToken(): Promise<string | null>;

/**
 * Token expiry buffer in milliseconds (30 seconds)
 *
 * Refresh tokens this many milliseconds BEFORE they expire
 * to account for network latency and clock skew.
 */
declare const TOKEN_EXPIRY_BUFFER_MS = 30000;
/** Session token lifetime in milliseconds (for React Query staleTime) */
declare const SESSION_TOKEN_LIFETIME_MS: number;

/**
 * Platform ID utilities for the Sylphx SDK
 *
 * Converts between raw UUIDs (used internally / in JWT sub claims) and
 * prefixed TypeID strings (used in all API responses and JWT pid claims).
 *
 * Uses TypeID spec v0.3.0 (Crockford base32, case-insensitive).
 * Also accepts legacy base58 format for backward compatibility.
 *
 * No external dependencies — pure TypeScript implementation of Crockford base32.
 *
 * @example
 * ```ts
 * import { encodeUserId, decodeUserId } from '@sylphx/sdk/nextjs'
 *
 * const prefixed = encodeUserId('018f4a3b-1c2d-7000-9abc-def012345678')
 * // => 'user_01h2xcejqtf2nbrexx3vqjhp41'
 *
 * const uuid = decodeUserId('user_01h2xcejqtf2nbrexx3vqjhp41')
 * // => '018f4a3b-1c2d-7000-9abc-def012345678'
 * ```
 */
/**
 * Encode a raw UUID as a prefixed TypeID user ID.
 *
 * @param uuid - Raw UUID string (with or without dashes)
 * @returns Prefixed TypeID: `user_<crockford_base32>`
 */
declare function encodeUserId(uuid: string): string;
/**
 * Decode a prefixed user ID back to a raw UUID.
 * Accepts both TypeID (current) and base58 (legacy) formats.
 *
 * @param prefixedId - Prefixed user ID: `user_<encoded>`
 * @returns Raw UUID string, or null if invalid
 */
declare function decodeUserId(prefixedId: string): string | null;

/**
 * Cookie Management for Next.js — Single Source of Truth
 *
 * Architecture: Cookie-Centric Auth (Clerk Pattern)
 * ================================================
 *
 * ALL auth state lives in cookies. Zero localStorage for auth.
 *
 * Cookie Structure:
 * - __sylphx_{namespace}_session  — HttpOnly JWT, 5 min (access token)
 * - __sylphx_{namespace}_refresh  — HttpOnly, 30 days (refresh token)
 * - __sylphx_{namespace}_user     — JS-readable, 5 min (user data for client hydration)
 *
 * Benefits:
 * 1. Single Source of Truth — no server/client state divergence
 * 2. XSS-safe — tokens never accessible to JavaScript
 * 3. Cross-tab sync — cookies shared across tabs automatically
 * 4. SSR works — auth() in Server Components reads cookies directly
 *
 * Security:
 * - Short token lifetime (5 min) like Clerk
 * - Server-side refresh in middleware
 * - SameSite=Lax for CSRF protection
 */

/**
 * Get cookie names for a given namespace
 *
 * Namespace is derived from the secret key environment (dev/stg/prod).
 * This prevents cookies from different environments colliding.
 *
 * @example
 * getCookieNames('sylphx_prod')
 * // Returns:
 * // {
 * //   SESSION: '__sylphx_prod_session',
 * //   REFRESH: '__sylphx_prod_refresh',
 * //   USER: '__sylphx_prod_user',
 * // }
 */
declare function getCookieNames(namespace: string): {
    /** HttpOnly JWT access token (5 min) */
    SESSION: string;
    /** HttpOnly refresh token (30 days) */
    REFRESH: string;
    /** JS-readable user data for client hydration (5 min) */
    USER: string;
    /** HttpOnly active organization ID used to preserve org-scoped sessions */
    ACTIVE_ORG_ID: string;
    /** HttpOnly active organization slug used to preserve org-scoped sessions */
    ACTIVE_ORG_SLUG: string;
};
/**
 * Session token lifetime (5 minutes like Clerk)
 */
declare const SESSION_TOKEN_LIFETIME: number;
/**
 * Refresh token lifetime (30 days)
 */
declare const REFRESH_TOKEN_LIFETIME: number;
/**
 * Active organization context lifetime (30 days).
 *
 * This matches refresh-token lifetime: the org preference is session-scoped
 * state, not a permanent user preference. Clearing auth clears this too.
 */
declare const ACTIVE_ORG_LIFETIME: number;
/**
 * Cookie options for HttpOnly tokens (session, refresh)
 *
 * Security features:
 * - httpOnly: true — Not accessible via JavaScript (XSS protection)
 * - secure: true in production — Only sent over HTTPS
 * - sameSite: 'lax' — CSRF protection while allowing navigation
 */
declare const SECURE_COOKIE_OPTIONS: {
    httpOnly: boolean;
    secure: boolean;
    sameSite: "lax";
    path: string;
};
/**
 * Cookie options for JS-readable user cookie
 *
 * This cookie contains only user info (no tokens) and enables:
 * - Client-side hydration without loading states
 * - Cross-tab sync via cookie visibility
 */
declare const USER_COOKIE_OPTIONS: {
    httpOnly: boolean;
    secure: boolean;
    sameSite: "lax";
    path: string;
};
/**
 * Cookie options for active organization context.
 *
 * Active org is not a secret, but it controls which org-scoped JWT the SDK
 * restores after refresh. Keep it HttpOnly so browser JavaScript cannot
 * silently steer server-side auth context outside the official switch-org
 * route.
 */
declare const ACTIVE_ORG_COOKIE_OPTIONS: {
    httpOnly: boolean;
    secure: boolean;
    sameSite: "lax";
    path: string;
};
/**
 * Auth cookies data returned by getAuthCookies
 */
interface AuthCookiesData {
    /** Access token from SESSION cookie (HttpOnly) */
    sessionToken: string | null;
    /** Refresh token from REFRESH cookie (HttpOnly) */
    refreshToken: string | null;
    /** User data from USER cookie (JS-readable) */
    user: User | null;
    /** Expiry timestamp from USER cookie */
    expiresAt: number | null;
}
/**
 * Get auth cookies from the request
 *
 * Used by auth() to read current auth state.
 */
declare function getAuthCookies(namespace: string): Promise<AuthCookiesData>;
/**
 * Set auth cookies from token response
 *
 * Sets all three cookies:
 * - SESSION: HttpOnly access token (5 min)
 * - REFRESH: HttpOnly refresh token (30 days)
 * - USER: JS-readable user data (5 min)
 *
 * @param namespace - Cookie namespace (e.g., 'sylphx_prod')
 * @param response - Token response from auth endpoint
 * @param options - Optional: custom expiresIn override
 */
declare function setAuthCookies(namespace: string, response: TokenResponse, options?: {
    sessionLifetime?: number;
}): Promise<void>;
/**
 * Clear all auth cookies
 *
 * Call on sign out to remove all auth state.
 */
declare function clearAuthCookies(namespace: string): Promise<void>;
/**
 * Check if session is expired
 *
 * Uses a 30 second buffer to account for network latency.
 */
declare function isSessionExpired(namespace: string): Promise<boolean>;
/**
 * Check if we have a refresh token (can potentially refresh)
 */
declare function hasRefreshToken(namespace: string): Promise<boolean>;

/**
 * Set auth cookies on a NextResponse (for middleware use)
 *
 * Unlike setAuthCookies() which uses next/headers, this works with NextResponse.
 * Use this in middleware where you need to modify cookies on the response.
 */
declare function setAuthCookiesMiddleware(response: NextResponse, namespace: string, tokens: TokenResponse): void;
/**
 * Clear auth cookies on a NextResponse (for middleware use)
 */
declare function clearAuthCookiesMiddleware(response: NextResponse, namespace: string): void;
/**
 * Parse user cookie value (for client-side use)
 */
declare function parseUserCookie(value: string): UserCookieData | null;

export { ACTIVE_ORG_COOKIE_OPTIONS, ACTIVE_ORG_LIFETIME, type AuthCookiesData, type AuthResult, REFRESH_TOKEN_LIFETIME, SECURE_COOKIE_OPTIONS, SESSION_TOKEN_LIFETIME, SESSION_TOKEN_LIFETIME_MS, type SylphxMiddlewareConfig, type SylphxOrganizationContextConfig, TOKEN_EXPIRY_BUFFER_MS, USER_COOKIE_OPTIONS, type UserCookieData, auth, clearAuthCookies, clearAuthCookiesMiddleware, configureServer, createMatcher, createSylphxMiddleware, currentUser, currentUserId, decodeUserId, encodeUserId, getAuthCookies, getAuthorizationUrl, getCookieNames, getNamespace, getSessionToken, handleCallback, hasRefreshToken, isSessionExpired, parseUserCookie, setAuthCookies, setAuthCookiesMiddleware, signOut, sylphxMiddleware, syncAuthToCookies };
