import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { jwtVerify } from 'jose';

const CUSTOMER_SESSION_COOKIE = 'customer_session';
const PUBLIC_ACCOUNT_PATHS = ['/account/login', '/account/register', '/account/forgot-password', '/account/reset-password'];

const ADMIN_SESSION_COOKIE = 'admin_session';
const PUBLIC_ADMIN_PATHS = ['/admin/login'];

// Protects everything under /admin with the shop owner's own login session —
// entirely separate cookie and secret from the customer auth below, so
// logging into one never grants access to the other.
async function checkAdminAuth(request: NextRequest, requestHeaders: Headers) {
  if (PUBLIC_ADMIN_PATHS.includes(request.nextUrl.pathname)) {
    return NextResponse.next({ request: { headers: requestHeaders } });
  }

  const token = request.cookies.get(ADMIN_SESSION_COOKIE)?.value;
  const secret = process.env.ADMIN_SESSION_SECRET;

  if (token && secret) {
    try {
      await jwtVerify(token, new TextEncoder().encode(secret));
      return NextResponse.next({ request: { headers: requestHeaders } });
    } catch {
      // fall through to redirect
    }
  }

  const loginUrl = new URL('/admin/login', request.url);
  loginUrl.searchParams.set('next', request.nextUrl.pathname);
  return NextResponse.redirect(loginUrl);
}

// Protects everything under /account (except the login/register/reset pages
// themselves) with a customer's own login session — entirely separate cookie
// and secret from the admin auth above, so one never grants access to the other.
async function checkCustomerAuth(request: NextRequest, requestHeaders: Headers) {
  if (PUBLIC_ACCOUNT_PATHS.includes(request.nextUrl.pathname)) {
    return NextResponse.next({ request: { headers: requestHeaders } });
  }

  const token = request.cookies.get(CUSTOMER_SESSION_COOKIE)?.value;
  const secret = process.env.SESSION_SECRET;

  if (token && secret) {
    try {
      await jwtVerify(token, new TextEncoder().encode(secret));
      return NextResponse.next({ request: { headers: requestHeaders } });
    } catch {
      // fall through to redirect
    }
  }

  const loginUrl = new URL('/account/login', request.url);
  loginUrl.searchParams.set('next', request.nextUrl.pathname);
  return NextResponse.redirect(loginUrl);
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Expose the path to server components (the root layout reads x-pathname to
  // decide whether to show the maintenance page). Edge middleware can't read the
  // DB, so the maintenance flag itself is checked in the layout, not here.
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-pathname', pathname);

  if (pathname.startsWith('/admin')) {
    return checkAdminAuth(request, requestHeaders);
  }
  if (pathname.startsWith('/account')) {
    return checkCustomerAuth(request, requestHeaders);
  }
  return NextResponse.next({ request: { headers: requestHeaders } });
}

export const config = {
  // Run on everything except static assets, so the x-pathname header is set on
  // every page. The auth branches above still only gate /admin and /account.
  matcher: ['/((?!_next/static|_next/image|favicon.ico|logo.png).*)'],
};
