import type { Handler } from 'hono';
import { getUserCount, createUser, replaceRoleGrants, USER_ROLES } from 'officerdb';
import { DEFAULT_ROLE_CAPABILITIES } from '@@/capabilities/registry';
import argon2 from 'argon2';
import * as errors from '@@/custom-errors';
import { rememberUser } from '@@/_middlewares';
import { validatePassword } from './validate-password';
import { validateUsername } from './validate-username';

// Single-step bootstrap for the one account Officer supports: the server owner is created directly as
// active, with no email-verification round-trip. Gated to an empty user table.
export const bootstrapHandler: Handler = async function (ctx) {
  const body = ctx.get('body');

  const userCount = await getUserCount();
  if (userCount > 0) throw errors.FORBIDDEN('Registration is closed');

  const email = body.email as string;
  const name = body.name as string;
  const username = body.username as string;
  const password = body.password as string;
  const confirmPassword = body.confirmPassword as string;

  if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
    throw errors.BAD_REQUEST('Invalid email address');
  }
  if (!name || !name.trim()) throw errors.BAD_REQUEST('Name is required');
  const validUsername = validateUsername(username);
  validatePassword(password);
  if (password !== confirmPassword) throw errors.BAD_REQUEST('Passwords do not match');

  const passwordHash = await argon2.hash(password);

  // The role is what makes this account the owner — isSuperAdmin and getOwnerUser both read it, and
  // nothing else confers it. Without this the first account would take the column's 'Member' default
  // and the platform would come up with no owner at all: no vault, no agent identity, and the web
  // origin locked to a Super Admin that does not exist. Bootstrap is gated on an empty user table
  // above, so this cannot promote anyone but the first account.
  const user = await createUser({
    email,
    password: passwordHash,
    name: name.trim(),
    username: validUsername,
    status: 'Active',
    role: 'Super Admin',
  });

  // Every other role starts with the baseline: terminal, chat and files at write. Done here because
  // bootstrap is the one moment that happens exactly once per install, so seeding cannot fight a later
  // revocation — take one of these away and nothing puts it back.
  //
  // Non-fatal. An owner who exists but whose roles hold nothing is a working server with a one-click fix;
  // failing bootstrap over it would leave a platform with no account at all.
  try {
    for (const role of USER_ROLES.filter((r) => r !== 'Super Admin')) {
      await replaceRoleGrants(
        role,
        DEFAULT_ROLE_CAPABILITIES.map((capability) => ({ capability, level: 'write' as const })),
      );
    }
  } catch (ex) {
    console.warn('[bootstrap] could not seed default role capabilities', ex);
  }

  // The launch-time snapshot was taken while the user table was still empty. Without this the owner's
  // very first sign-in would be filed as an unknown identity.
  rememberUser(user);

  return ctx.json({ ok: true });
};
