<% if (i18nEnabled) { %>
import { NextRequest, NextResponse } from 'next/server';

const TOKEN_COOKIE = 'brainerce_customer_token';
const PROTECTED_PATHS = ['/account'];
const supportedLocales = <%- supportedLocales %>;
const defaultLocale = '<%= defaultLocale %>';

function getLocaleFromPath(pathname: string): string | null {
  const segment = pathname.split('/')[1];
  return supportedLocales.includes(segment) ? segment : null;
}

function generateNonce(): string {
  const bytes = new Uint8Array(16);
  crypto.getRandomValues(bytes);
  let binary = '';
  for (const b of bytes) binary += String.fromCharCode(b);
  return btoa(binary);
}

// The Brainerce AI chat widget streams chat directly from the browser, so the
// API origin must be allowed in connect-src (derived from env so local/staging
// setups work without editing this file).
function brainerceApiOrigin(): string {
  try {
    return new URL(process.env.NEXT_PUBLIC_BRAINERCE_API_URL || 'https://api.brainerce.com').origin;
  } catch {
    return 'https://api.brainerce.com';
  }
}

// Beacon/XHR endpoints for the merchant's marketing tags (GA4, GTM, Meta,
// TikTok). Only `connect-src` needs them: `script-src` runs with
// 'strict-dynamic', under which host allowlists are IGNORED and trust
// propagates from the nonce'd bundle to the tag scripts it injects — so
// adding hosts there would be dead config. Without these entries the tags
// load fine and then every hit is blocked, which fails silently: the
// dashboard shows a connected pixel and the ad platform records nothing.
//
// Fixed list, not read from store config: middleware cannot see which apps a
// merchant connected without a fetch on every request, and these are the same
// well-known vendor origins for every store.
const MARKETING_TAG_ORIGINS = [
  // Google (gtag.js, GTM, GA4 collect, Ads conversion pings)
  'https://www.googletagmanager.com',
  'https://www.google-analytics.com',
  'https://*.google-analytics.com',
  'https://*.analytics.google.com',
  'https://stats.g.doubleclick.net',
  'https://www.google.com',
  // Meta pixel
  'https://connect.facebook.net',
  'https://www.facebook.com',
  // TikTok pixel
  'https://analytics.tiktok.com',
].join(' ');

function buildCsp(nonce: string): string {
  const isDev = process.env.NODE_ENV === 'development';
  // Next dev uses webpack's eval-source-map devtool, which requires 'unsafe-eval'
  // to execute module code. Prod builds never eval, so this only loosens dev.
  const scriptSrc = isDev
    ? `script-src 'self' 'nonce-${nonce}' 'strict-dynamic' 'unsafe-eval'`
    : `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`;
  return [
    "default-src 'self'",
    scriptSrc,
    "style-src 'self' 'unsafe-inline' https://cdn.meshulam.co.il",
    "img-src 'self' data: blob: https:",
    "font-src 'self' data:",
    "frame-src 'self' https://meshulam.co.il https://*.meshulam.co.il https://grow.link https://*.grow.link https://grow.security https://*.grow.security https://creditguard.co.il https://*.creditguard.co.il https://js.stripe.com https://hooks.stripe.com https://pay.google.com https://secure.cardcom.solutions https://checkout.stripe.com https://www.paypal.com https://www.sandbox.paypal.com https://www.youtube.com https://www.youtube-nocookie.com https://player.vimeo.com https://*.brainerce.com",
    `connect-src 'self' ${brainerceApiOrigin()} https://api.brainerce.com https://*.meshulam.co.il https://grow.link https://*.grow.link https://*.grow.security https://pay.google.com https://*.stripe.com https://*.creditguard.co.il ${MARKETING_TAG_ORIGINS}`,
    "worker-src 'self' blob:",
    // 'self' (not 'none') so iframe-based payment providers (e.g. Cardcom)
    // can redirect the iframe back to /payment-complete on the storefront
    // itself after a successful charge.
    "frame-ancestors 'self'",
    "base-uri 'self'",
    "form-action 'self'",
    "object-src 'none'",
    'upgrade-insecure-requests',
  ].join('; ');
}

function applyCspHeaders(response: NextResponse, nonce: string): NextResponse {
  response.headers.set('Content-Security-Policy', buildCsp(nonce));
  response.headers.set('x-nonce', nonce);
  return response;
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Skip static files and API routes
  if (
    pathname.startsWith('/api/') ||
    pathname.startsWith('/_next/') ||
    pathname.includes('.')
  ) {
    return NextResponse.next();
  }

  const nonce = generateNonce();
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);

  const pathnameLocale = getLocaleFromPath(pathname);

  // As-needed locale routing:
  //   /foo            → rewrite to /{defaultLocale}/foo (URL stays clean)
  //   /{default}/foo  → 308-redirect to /foo (canonical, avoids duplicate content)
  //   /{other}/foo    → proceed as-is
  //
  // Effective locale used for auth/header is `defaultLocale` for clean URLs
  // and the explicit prefix otherwise.
  const effectiveLocale = pathnameLocale || defaultLocale;
  const pathWithoutLocale = pathnameLocale
    ? pathname.slice(`/${pathnameLocale}`.length) || '/'
    : pathname;

  // Auth protection — check before any rewrite/redirect so the login
  // redirect lands on the correct canonical URL.
  const isProtected = PROTECTED_PATHS.some((p) => pathWithoutLocale.startsWith(p));
  if (isProtected) {
    const token = request.cookies.get(TOKEN_COOKIE);
    if (!token?.value) {
      const loginPath =
        effectiveLocale === defaultLocale ? '/login' : `/${effectiveLocale}/login`;
      return applyCspHeaders(NextResponse.redirect(new URL(loginPath, request.url)), nonce);
    }
  }

  // Canonicalize: strip the default-locale prefix so /en/foo → /foo.
  if (pathnameLocale === defaultLocale) {
    const url = request.nextUrl.clone();
    url.pathname = pathWithoutLocale;
    return applyCspHeaders(NextResponse.redirect(url, 308), nonce);
  }

  // No locale prefix → rewrite internally to /{defaultLocale}/...
  // so the [locale] segment resolves; URL in the bar stays unprefixed.
  if (!pathnameLocale) {
    const url = request.nextUrl.clone();
    url.pathname = `/${defaultLocale}${pathname === '/' ? '' : pathname}`;
    const response = NextResponse.rewrite(url, { request: { headers: requestHeaders } });
    response.headers.set('x-locale', defaultLocale);
    return applyCspHeaders(response, nonce);
  }

  // Non-default locale prefix → proceed as-is.
  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set('x-locale', pathnameLocale);
  return applyCspHeaders(response, nonce);
}

export const config = {
  matcher: ['/((?!_next|api|.*\\..*).*)'],
};
<% } else { %>
import { NextRequest, NextResponse } from 'next/server';

const TOKEN_COOKIE = 'brainerce_customer_token';

/** Routes that require customer authentication */
const PROTECTED_PATHS = ['/account'];

function generateNonce(): string {
  const bytes = new Uint8Array(16);
  crypto.getRandomValues(bytes);
  let binary = '';
  for (const b of bytes) binary += String.fromCharCode(b);
  return btoa(binary);
}

// The Brainerce AI chat widget streams chat directly from the browser, so the
// API origin must be allowed in connect-src (derived from env so local/staging
// setups work without editing this file).
function brainerceApiOrigin(): string {
  try {
    return new URL(process.env.NEXT_PUBLIC_BRAINERCE_API_URL || 'https://api.brainerce.com').origin;
  } catch {
    return 'https://api.brainerce.com';
  }
}

// Beacon/XHR endpoints for the merchant's marketing tags (GA4, GTM, Meta,
// TikTok). Only `connect-src` needs them: `script-src` runs with
// 'strict-dynamic', under which host allowlists are IGNORED and trust
// propagates from the nonce'd bundle to the tag scripts it injects — so
// adding hosts there would be dead config. Without these entries the tags
// load fine and then every hit is blocked, which fails silently: the
// dashboard shows a connected pixel and the ad platform records nothing.
//
// Fixed list, not read from store config: middleware cannot see which apps a
// merchant connected without a fetch on every request, and these are the same
// well-known vendor origins for every store.
const MARKETING_TAG_ORIGINS = [
  // Google (gtag.js, GTM, GA4 collect, Ads conversion pings)
  'https://www.googletagmanager.com',
  'https://www.google-analytics.com',
  'https://*.google-analytics.com',
  'https://*.analytics.google.com',
  'https://stats.g.doubleclick.net',
  'https://www.google.com',
  // Meta pixel
  'https://connect.facebook.net',
  'https://www.facebook.com',
  // TikTok pixel
  'https://analytics.tiktok.com',
].join(' ');

function buildCsp(nonce: string): string {
  const isDev = process.env.NODE_ENV === 'development';
  // Next dev uses webpack's eval-source-map devtool, which requires 'unsafe-eval'
  // to execute module code. Prod builds never eval, so this only loosens dev.
  const scriptSrc = isDev
    ? `script-src 'self' 'nonce-${nonce}' 'strict-dynamic' 'unsafe-eval'`
    : `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`;
  return [
    "default-src 'self'",
    scriptSrc,
    "style-src 'self' 'unsafe-inline' https://cdn.meshulam.co.il",
    "img-src 'self' data: blob: https:",
    "font-src 'self' data:",
    "frame-src 'self' https://meshulam.co.il https://*.meshulam.co.il https://grow.link https://*.grow.link https://grow.security https://*.grow.security https://creditguard.co.il https://*.creditguard.co.il https://js.stripe.com https://hooks.stripe.com https://pay.google.com https://secure.cardcom.solutions https://checkout.stripe.com https://www.paypal.com https://www.sandbox.paypal.com https://www.youtube.com https://www.youtube-nocookie.com https://player.vimeo.com https://*.brainerce.com",
    `connect-src 'self' ${brainerceApiOrigin()} https://api.brainerce.com https://*.meshulam.co.il https://grow.link https://*.grow.link https://*.grow.security https://pay.google.com https://*.stripe.com https://*.creditguard.co.il ${MARKETING_TAG_ORIGINS}`,
    "worker-src 'self' blob:",
    // 'self' (not 'none') so iframe-based payment providers (e.g. Cardcom)
    // can redirect the iframe back to /payment-complete on the storefront
    // itself after a successful charge.
    "frame-ancestors 'self'",
    "base-uri 'self'",
    "form-action 'self'",
    "object-src 'none'",
    'upgrade-insecure-requests',
  ].join('; ');
}

function applyCspHeaders(response: NextResponse, nonce: string): NextResponse {
  response.headers.set('Content-Security-Policy', buildCsp(nonce));
  response.headers.set('x-nonce', nonce);
  return response;
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Skip static files and API routes
  if (
    pathname.startsWith('/api/') ||
    pathname.startsWith('/_next/') ||
    pathname.includes('.')
  ) {
    return NextResponse.next();
  }

  const nonce = generateNonce();
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);

  const isProtected = PROTECTED_PATHS.some((p) => pathname.startsWith(p));

  if (isProtected) {
    const token = request.cookies.get(TOKEN_COOKIE);
    if (!token?.value) {
      const loginUrl = new URL('/login', request.url);
      return applyCspHeaders(NextResponse.redirect(loginUrl), nonce);
    }
  }

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  return applyCspHeaders(response, nonce);
}

export const config = {
  matcher: ['/((?!_next|api|.*\\..*).*)'],
};
<% } %>
