import { defineMiddleware } from 'astro:middleware';
import { env } from 'cloudflare:workers';
import type { Querier } from '@platform-modules/db';
import { enforceStorefrontRateLimit, type StorefrontLimiterEnv } from './lib/rate-limit.js';
import { getSession, type SessionEnv } from './lib/session.js';
import { getDb, type DbEnv } from './lib/db.js';
import { isInstalled } from './lib/settings.js';
import { isInstallAssetPath } from './lib/install.js';

function isAdminPath(pathname: string): boolean {
  return pathname === '/admin' || pathname.startsWith('/admin/');
}

function isAdminApiPath(pathname: string): boolean {
  return pathname === '/api/admin' || pathname.startsWith('/api/admin/');
}

function isAccountPath(pathname: string): boolean {
  return pathname === '/account' || pathname.startsWith('/account/');
}

function hasOwnerAccess(role: string): boolean {
  return role === 'owner';
}

function isInstallExemptPath(pathname: string): boolean {
  return (
    pathname === '/install' ||
    pathname.startsWith('/install/') ||
    pathname === '/api/install' ||
    isInstallAssetPath(pathname)
  );
}

export const onRequest = defineMiddleware(async (context, next) => {
  const pathname = context.url.pathname;
  const cfEnv = env as (SessionEnv & StorefrontLimiterEnv & DbEnv) | undefined;

  // Install guard: unconfigured stores route to /install (skip install routes + static assets).
  if (!isInstallExemptPath(pathname) && cfEnv && (cfEnv.DB || cfEnv.DATABASE_URL)) {
    try {
      const { db } = getDb(cfEnv);
      const installed = await isInstalled(db as unknown as Querier);
      if (!installed) {
        return context.redirect('/install');
      }
    } catch {
      // Fail-open on transient DB read errors — do not brick the whole site.
    }
  }

  if (pathname === '/install' || pathname.startsWith('/install/')) {
    return next();
  }

  if (cfEnv) {
    const limited = await enforceStorefrontRateLimit(cfEnv, context.request);
    if (limited) return limited;
  }

  if (isAdminPath(pathname)) {
    const session = cfEnv ? await getSession(cfEnv, context.cookies) : null;
    if (!session || !hasOwnerAccess(session.role)) {
      const nextPath = encodeURIComponent(pathname);
      return context.redirect(`/login?next=${nextPath}`);
    }
    return next();
  }

  // Admin API gate — owner only; returns JSON 401/403, not HTML redirect
  if (isAdminApiPath(pathname)) {
    const session = cfEnv ? await getSession(cfEnv, context.cookies) : null;
    if (!session) {
      return new Response(JSON.stringify({ error: { code: 'UNAUTHORIZED', message: 'Authentication required' } }), {
        status: 401,
        headers: { 'Content-Type': 'application/json' },
      });
    }
    if (!hasOwnerAccess(session.role)) {
      return new Response(JSON.stringify({ error: { code: 'FORBIDDEN', message: 'Owner role required' } }), {
        status: 403,
        headers: { 'Content-Type': 'application/json' },
      });
    }
    return next();
  }

  if (isAccountPath(pathname)) {
    const session = cfEnv ? await getSession(cfEnv, context.cookies) : null;
    if (!session) {
      const nextPath = encodeURIComponent(pathname);
      return context.redirect(`/login?next=${nextPath}`);
    }
    return next();
  }

  return next();
});
