import { NextResponse, type NextProxy } from 'next/server';
import { isMarkdownPreferred, rewritePath } from 'fumadocs-core/negotiation';
import { createI18nMiddleware } from 'fumadocs-core/i18n/middleware';
import { getSessionCookie } from 'better-auth/cookies';
import { i18n } from '@/lib/i18n';
import { docsContentRoute, docsRoute } from '@/lib/shared';

const { rewrite: rewriteDocs } = rewritePath(
  `${docsRoute}{/*path}`,
  `${docsContentRoute}{/*path}/content.md`,
);
const { rewrite: rewriteSuffix } = rewritePath(
  `${docsRoute}{/*path}.md`,
  `${docsContentRoute}{/*path}/content.md`,
);

const i18nMiddleware = createI18nMiddleware(i18n);

/**
 * Les routes d'export servent des agents, pas des lecteurs : elles vivent hors
 * de `[lang]` et restent en anglais. Sans cette exclusion, le middleware i18n
 * les préfixerait d'une langue et elles répondraient 404, mesuré.
 *
 * Elles vérifient elles-mêmes la session et répondent 401. Les rediriger vers un
 * écran de connexion n'aurait aucun sens pour un client qui attend du texte.
 */
const exportRoutes = ['/llms.txt', '/llms-full.txt', '/llms.mdx'];

/**
 * Le seul chemin atteignable sans session. Il est testé sur le segment de fin
 * pour couvrir aussi bien `/login` que `/th/login`. Les endpoints
 * d'authentification, eux, sont hors du proxy, voir `config.matcher`.
 */
function isPublic(pathname: string): boolean {
  return pathname === '/login' || pathname.endsWith('/login');
}

const proxy: NextProxy = (request, context) => {
  const { pathname } = request.nextUrl;

  // La négociation markdown passe en premier : elle vise les routes d'export,
  // qui ne doivent recevoir ni préfixe de langue ni redirection.
  const suffixed = rewriteSuffix(pathname);
  if (suffixed) {
    return NextResponse.rewrite(new URL(suffixed, request.nextUrl));
  }

  if (isMarkdownPreferred(request)) {
    const negotiated = rewriteDocs(pathname);

    if (negotiated) {
      return NextResponse.rewrite(new URL(negotiated, request.nextUrl), {
        // this URL has two representations, selected by `Accept`
        headers: { Vary: 'Accept' },
      });
    }
  }

  if (exportRoutes.some((route) => pathname === route || pathname.startsWith(`${route}/`))) {
    return NextResponse.next();
  }

  /*
    Contrôle **optimiste** : il ne lit qu'un cookie, sans requête SQL, pour
    éviter d'afficher une page vide à qui n'est pas connecté. Un cookie forgé
    franchirait cette couche : ce sont les pages et les routes qui refusent
    réellement, en validant la session côté serveur.
  */
  if (!isPublic(pathname) && !getSessionCookie(request)) {
    const url = new URL('/login', request.nextUrl);
    if (pathname !== '/') url.searchParams.set('next', pathname);

    return NextResponse.redirect(url);
  }

  // Le contexte est transmis tel quel : le middleware i18n est typé `NextProxy`
  // et Next 16 le lui passe en second argument.
  return i18nMiddleware(request, context);
};

export default proxy;

export const config = {
  /*
    Les routes d'API sont hors du proxy : elles n'ont pas de langue, et une
    redirection vers l'écran de connexion leur ferait renvoyer du HTML à un
    client qui attend du JSON. Chacune vérifie la session et répond 401.
  */
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico|robots.txt).*)'],
};
