import "server-only";

import type { RowDataPacket } from "mysql2/promise";

import { ensureOfficialMailSchema, getDbPool } from "@/lib/db";
import { getRequestClientIp } from "@/lib/request-client-ip";

export type AuthActivityEventType = "find_id" | "login";
export type AuthActivitySource = "app" | "web";

type AuthActivityLookup = "login_email" | "recovery_email";

type AuthRequestMetadata = {
  ipAddress: string | null;
  source: AuthActivitySource;
  userAgent: string | null;
};

type RecordUserAuthActivityInput = AuthRequestMetadata & {
  eventType: AuthActivityEventType;
  identityEmail: string;
  lookup: AuthActivityLookup;
  outcome: string;
};

export function getAuthRequestMetadata(
  requestHeaders: Pick<Headers, "get">,
  source: AuthActivitySource,
): AuthRequestMetadata {
  const ipAddress = getRequestClientIp(requestHeaders);
  const userAgent = requestHeaders.get("user-agent")?.trim().slice(0, 512) || null;

  return { ipAddress, source, userAgent };
}

export async function recordUserAuthActivity(
  input: RecordUserAuthActivityInput,
) {
  const identityEmail = input.identityEmail.trim().toLowerCase().slice(0, 320);

  if (!identityEmail) {
    return;
  }

  try {
    await ensureOfficialMailSchema();
    const lookupColumn =
      input.lookup === "recovery_email" ? "recovery_email" : "email";
    const verifiedRecoveryCondition =
      input.lookup === "recovery_email"
        ? "AND recovery_email_verified_at IS NOT NULL"
        : "";
    const [userRows] = await getDbPool().query<
      (RowDataPacket & { id: number })[]
    >(
      `
        SELECT id
        FROM users
        WHERE LOWER(${lookupColumn}) = ?
          ${verifiedRecoveryCondition}
        ORDER BY id ASC
        LIMIT 50
      `,
      [identityEmail],
    );

    if (userRows.length === 0) {
      return;
    }

    const values = userRows.map((row) => [
      Number(row.id),
      input.eventType,
      input.outcome.slice(0, 32),
      input.source,
      identityEmail,
      input.ipAddress,
      input.userAgent,
    ]);

    await getDbPool().query(
      `
        INSERT INTO user_auth_activity_events (
          user_id,
          event_type,
          outcome,
          source,
          identity_email,
          ip_address,
          user_agent
        ) VALUES ?
      `,
      [values],
    );
  } catch (error) {
    console.error("Unable to record user authentication activity", error);
  }
}
