// packages/functions/src/firebase/auth/setCustomClaims.ts

/**
 * @fileoverview Set custom claims Firebase function
 * @description Firebase callable function for setting custom user claims
 *
 * @version 0.0.1
 * @since 0.0.1
 * @author AMBROISE PARK Consulting
 */

import {
  getFirebaseAdminAuth,
  getFirebaseAdminFirestore,
} from '@donotdev/firebase/server';
import * as v from 'valibot';
import { createBaseFunction } from '../baseFunction.js';
import { AUTH_CONFIG } from '../config/constants.js';

import type { CallableRequest } from 'firebase-functions/v2/https';

const setCustomClaimsSchema = v.object({
  customClaims: v.record(v.string(), v.any()),
  idempotencyKey: v.optional(v.string()),
});

/**
 * Business logic for setting custom claims
 * Base function handles: validation, auth, rate limiting, monitoring
 *
 * @version 0.0.1
 * @since 0.0.1
 * @author AMBROISE PARK Consulting
 */
async function setCustomClaimsLogic(
  data: v.InferOutput<typeof setCustomClaimsSchema>,
  context: {
    uid: string;
    request: CallableRequest<v.InferOutput<typeof setCustomClaimsSchema>>;
  }
) {
  const { customClaims, idempotencyKey } = data;

  if (!customClaims || typeof customClaims !== 'object') {
    throw new Error('customClaims must be an object');
  }

  // Idempotency check if key provided
  if (idempotencyKey) {
    const db = getFirebaseAdminFirestore();
    const idempotencyRef = db
      .collection('idempotency')
      .doc(`claims_${idempotencyKey}`);

    const idempotencyDoc = await idempotencyRef.get();
    if (idempotencyDoc.exists) {
      return idempotencyDoc.data()?.result;
    }
  }

  const user = await getFirebaseAdminAuth().getUser(context.uid);
  const currentClaims = user.customClaims || {};

  // Merge with existing claims
  const updatedClaims = { ...currentClaims, ...customClaims };

  await getFirebaseAdminAuth().setCustomUserClaims(context.uid, updatedClaims);

  const result = { success: true, customClaims: updatedClaims };

  // Store result for idempotency if key provided
  if (idempotencyKey) {
    const db = getFirebaseAdminFirestore();
    const idempotencyRef = db
      .collection('idempotency')
      .doc(`claims_${idempotencyKey}`);
    await idempotencyRef.set({
      result,
      processedAt: new Date().toISOString(),
      processedBy: context.uid,
    });
  }

  return result;
}

/**
 * Sets custom claims for a user
 * Base function handles all common concerns automatically
 *
 * @version 0.0.1
 * @since 0.0.1
 * @author AMBROISE PARK Consulting
 */
export const setCustomClaims = (
  customSchema?: v.BaseSchema<unknown, any, v.BaseIssue<unknown>>
) => {
  const schema = customSchema || setCustomClaimsSchema;
  return createBaseFunction(
    AUTH_CONFIG,
    schema,
    'set_custom_claims',
    setCustomClaimsLogic
  );
};
