Source: Router/searchData/controller.js

/**
 * SearchData Controller Layer
 * 
 * This controller handles HTTP requests and responses for search operations.
 * It serves as the interface between the HTTP layer and the search service,
 * managing request validation, response formatting, and error handling.
 * 
 * Key responsibilities:
 * - HTTP request/response handling
 * - Input validation and sanitization
 * - Error response formatting
 * - Service layer coordination
 * - Status code management
 * 
 * Authentication requirements:
 * - All endpoints require authenticated session
 * - Visibility is enforced at service layer
 * 
 * @module SearchDataController
 */

// @ts-check
/**
 * @import {ExpressRequestAuthorized, ExpressResponse} from './../../types.js'
 */

import { HEX2uuid } from '@commtool/sql-query';
import { errorLoggerRead } from '../../utils/requestLogger.js';
import * as searchService from './service.js';

/**
 * Search all entity types with fulltext search
 * 
 * This endpoint performs a comprehensive search across multiple entity types
 * using MySQL fulltext search. It supports filtering by type, gender, stage,
 * and hierarchy, as well as visibility restrictions based on user permissions.
 * 
 * @param {ExpressRequestAuthorized} req - Express request object
 * @param {ExpressResponse} res - Express response object
 * 
 * HTTP Status Codes:
 * - 200: Search completed successfully
 * - 500: Internal server error
 * 
 * Response format:
 * - Array of search results with title, value, key, type, validFrom
 * - Or {success: false, message: error} on error
 * 
 * Authentication: Requires authenticated session
 * Logging: Uses errorLoggerRead for error tracking
 */
export const searchAll = async (req, res) => {
    try {
        const searchQuery = req.query.search;
        const result = await searchService.searchAllEntities(
            searchQuery, 
            req.session, 
            req.query
        );
        res.json(result);
    } catch (e) {
        errorLoggerRead(e);
        res.json({ success: false, message: e });
    }
};

/**
 * Search specific entity type with fulltext search
 * 
 * This endpoint performs type-specific searches with optimized queries
 * for different entity types (member, person, extern, group, list, etc.).
 * 
 * @param {ExpressRequestAuthorized} req - Express request object
 * @param {ExpressResponse} res - Express response object
 * 
 * HTTP Status Codes:
 * - 200: Search completed successfully
 * - 500: Internal server error
 * 
 * Response format:
 * - Array of {title, value, key, type} objects
 * 
 * Authentication: Requires authenticated session
 * Logging: Uses errorLoggerRead for error tracking
 */
export const searchByType = async (req, res) => {
    try {
        const searchQuery = req.query.search;
        const type = req.params.type;
        let result = [];

        // Route to appropriate search service based on type
        switch (type) {
            case 'member':
                result = await searchService.searchMembers(searchQuery, req.session, req.query);
                break;

            case 'extern':
                result = await searchService.searchExtern(searchQuery, req.session, req.query);
                break;

            case 'person':
                result = await searchService.searchPersons(searchQuery, req.session, req.query);
                break;

            case 'group':
                result = await searchService.searchGroups(searchQuery, req.session, req.query);
                break;

            case 'list':
            case 'dlist':
            case 'email':
                if (['list', 'dlist', 'email'].includes(type)) {
                    result = await searchService.searchLists(searchQuery, type, req.session, req.query);
                }
                break;

            default:
                result = await searchService.searchGeneric(searchQuery, type, req.session, req.query);
                break;
        }

        // Format results for API response
        if (result) {
            res.json(result.map((r, Index) => ({ 
                title: r.title, 
                value: HEX2uuid(r.value), 
                key: Index, 
                type: r.type 
            })));
        } else {
            res.json([]);
        }
    } catch (e) {
        errorLoggerRead(e);
        res.json({ success: false, message: e });
    }
};

/**
 * Search entities using semantic vector similarity (AI embeddings)
 * 
 * This endpoint performs semantic search using vector similarity, which finds
 * entities that are semantically similar to the search query even if they don't
 * contain the exact keywords. This uses AI embeddings stored in the database.
 * 
 * @param {ExpressRequestAuthorized} req - Express request object
 * @param {ExpressResponse} res - Express response object
 * 
 * HTTP Status Codes:
 * - 200: Search completed successfully
 * - 400: Missing or invalid search query
 * - 500: Internal server error
 * 
 * Response format:
 * - Array of {title, value, key, type, similarity, distance, model} objects
 * - Or {success: false, message, error} on error
 * 
 * Authentication: Requires authenticated session
 * Logging: Uses errorLoggerRead for error tracking
 */
export const searchEmbedding = async (req, res) => {
    try {
        const searchQuery = String(req.query.search || '');
        
        if (!searchQuery) {
            return res.status(400).json({ 
                success: false, 
                message: 'Search query is required' 
            });
        }

        const formattedResults = await searchService.searchBySemantic(
            searchQuery, 
            req.session, 
            req.query
        );

        res.json(formattedResults);

    } catch (error) {
        errorLoggerRead(error);
        res.status(500).json({ 
            success: false, 
            message: 'Embedding search failed',
            error: error.message 
        });
    }
};