import { HttpError } from "@batch-cooking/error-tools";
import { type AdminLoginInput, type AdminUserView, ErrorCode } from "@batch-cooking/shared";
import argon2 from "argon2";
import { env } from "../../config/env.js";
import { prisma } from "../../db/prisma.js";
import { signAdminToken } from "../../lib/admin-jwt.js";
import { toSafeAdmin } from "../../lib/safe-admin.js";

/** Result of a successful admin login: the safe admin view plus the signed admin session JWT to set as a cookie. */
interface AdminAuthResult {
  admin: AdminUserView;
  token: string;
}

// Same reasoning as `auth.service.ts`'s `hashOptions`: argon2's real
// defaults are deliberately expensive; the test suite hashes/verifies
// against throwaway data many times per run, so a cheaper cost keeps it
// fast without weakening anything real. Never applies outside NODE_ENV=test.
const testHashOptions = { memoryCost: 8192, timeCost: 2, parallelism: 1 };
const hashOptions = env.NODE_ENV === "test" ? testHashOptions : undefined;

/** Exposed so `src/scripts/create-admin.ts` hashes exactly the same way `login` verifies. */
export function hashAdminPassword(password: string): Promise<string> {
  return argon2.hash(password, hashOptions);
}

/**
 * Verifies an admin operator's credentials, stamps `lastLoginAt`, and
 * issues a fresh admin session token.
 *
 * @throws {HttpError} `401 INVALID_CREDENTIALS` for either an unknown email
 *   or a wrong password — deliberately indistinguishable, same reasoning as
 *   `auth.service.ts`'s `login`.
 */
export async function adminLogin(input: AdminLoginInput): Promise<AdminAuthResult> {
  try {
    const admin = await prisma.adminUser.findUnique({ where: { email: input.email } });

    if (!admin || !(await argon2.verify(admin.passwordHash, input.password))) {
      throw new HttpError(401, ErrorCode.INVALID_CREDENTIALS, "Invalid email or password");
    }

    const updated = await prisma.adminUser.update({
      where: { id: admin.id },
      data: { lastLoginAt: new Date() },
    });

    const token = signAdminToken({
      adminUserId: updated.id,
      tokenVersion: updated.tokenVersion,
    });
    return { admin: toSafeAdmin(updated), token };
  } catch (err) {
    // Rethrown as-is — `wrapAsyncHandler`/the error middleware handles it,
    // this service layer just isn't allowed a bare `await` per the repo's
    // async/try-catch convention.
    throw err;
  }
}
