// packages/functions/src/firebase/crud/get.ts

/**
 * @fileoverview Generic function to retrieve a single entity.
 * @description Provides a reusable implementation for retrieving documents from Firestore with visibility filtering.
 *
 * @version 0.0.1
 * @since 0.0.1
 * @author AMBROISE PARK Consulting
 */

import * as v from 'valibot';

import { transformFirestoreData } from '../../shared/index.js';
import { filterVisibleFields } from '../../shared/index.js';
import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';

import { DoNotDevError } from '../../shared/utils.js';
import { createBaseFunction } from '../baseFunction.js';
import { CRUD_CONFIG } from '../config/constants.js';

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

/**
 * Generic business logic for getting entities
 * Base function handles: validation, auth, rate limiting, monitoring
 */
function getEntityLogicFactory(
  collection: string,
  documentSchema: v.BaseSchema<unknown, any, v.BaseIssue<unknown>>
) {
  return async function getEntityLogic(
    data: { id: string },
    context: { uid: string; request: CallableRequest<any> }
  ) {
    const { id } = data;

    // Get the document reference
    const db = getFirebaseAdminFirestore();
    const docRef = db.collection(collection).doc(id);

    // Retrieve the document
    const doc = await docRef.get();

    // Check if the document exists
    if (!doc.exists) {
      throw new DoNotDevError('Entity not found', 'not-found');
    }

    // Check if the user is an admin
    const isAdmin = context.request.auth?.token?.isAdmin === true;

    // Filter fields based on visibility and user role
    const filteredData = filterVisibleFields(
      doc.data() || {},
      documentSchema,
      isAdmin
    );

    // Transform the document data back to the application format
    return transformFirestoreData({
      id: doc.id,
      ...filteredData,
    });
  };
}

/**
 * Generic function to get entities from any Firestore collection
 * @param collection - The Firestore collection name
 * @param documentSchema - The Valibot schema for document validation
 * @param customSchema - Optional custom request schema
 * @returns Firebase callable function
 */
export const getEntity = (
  collection: string,
  documentSchema: v.BaseSchema<unknown, any, v.BaseIssue<unknown>>,
  customSchema?: v.BaseSchema<unknown, any, v.BaseIssue<unknown>>
) => {
  const requestSchema =
    customSchema ||
    v.object({
      id: v.pipe(v.string(), v.minLength(1)),
    });

  return createBaseFunction(
    CRUD_CONFIG,
    requestSchema,
    'get_entity',
    getEntityLogicFactory(collection, documentSchema)
  );
};
