import type { Handler } from 'hono';
import { getUserByEmail, getPasskeysByUserIdAndOrigin } from 'officerdb';
import { sign } from '@@/jwt';
import argon2 from 'argon2';
import * as errors from '@@/custom-errors';
import { isLockdown, noteBlocked } from './panic';

const TEST_USERS: number[] = [];

export const signinHandler: Handler = async function (ctx) {
  const { email, password } = ctx.get('body');
  // A caller that sends neither Origin nor Referer — a server-to-server client, curl — leaves this
  // undefined. It was once unreachable: origin validation rejected those requests before this handler
  // ran, so the value was always a string by the time anything touched it. Then the flag that disabled
  // that check defaulted to on, and `undefined` reached both a SQL parameter and `.startsWith`. Origin
  // validation is gone entirely as of 2026-08-13, so undefined is now the ordinary case rather than the
  // edge one. Normalising to '' keeps every downstream use honest: no passkey is registered against the
  // empty origin, so an origin-less caller falls through to password auth, which is what it wants.
  const origin = (ctx.get('origin') as string | undefined) ?? '';

  // Panic lockdown active → refuse all logins (looks like a normal failed login).
  if (isLockdown()) {
    noteBlocked('login attempt');
    throw errors.UNAUTHORIZED();
  }

  const dbUser = await getUserByEmail(email);
  if (!dbUser) throw errors.UNAUTHORIZED();

  const passkeys = await getPasskeysByUserIdAndOrigin(dbUser.id, origin);

  if (!dbUser.password) throw errors.UNAUTHORIZED();
  const { status } = dbUser;
  if (status !== 'Active') throw errors.UNAUTHORIZED();
  const isValidPassword = TEST_USERS.includes(dbUser.id) || (await argon2.verify(dbUser.password, password));
  if (!isValidPassword) throw errors.UNAUTHORIZED();

  // There used to be a check here refusing any non-owner signing in through the web or mobile platform
  // origin. It is gone deliberately: onboarding members who use the platform in a browser is the point,
  // and what they can reach once inside is decided by their role's capabilities at every request. A rule
  // that let a member hold a Gitea grant they could never sign in to use was not defence, just a wall.

  const { id, name, username } = dbUser;

  const tokenUser = { id, email, name, username, passkeys: passkeys.length };

  if (passkeys.length > 0 && !origin.startsWith('chrome-extension://') && !TEST_USERS.includes(dbUser.id)) {
    return ctx.json({ user: tokenUser });
  }

  const token = await sign(tokenUser);

  if (origin.startsWith('chrome-extension://')) {
    // console.log('token', token);
  }

  return ctx.json({ token, user: tokenUser });
};
