// @ts-check
/**
* @import {ExpressRequestAuthorized, ExpressResponse} from '../types.js'
*/
/**
* @module person
* @description Person/Member Management Router
*
* This router provides comprehensive endpoints for managing persons/members within the
* member management system. It handles all aspects of person data management including
* profile information, group memberships, historical tracking, and administrative functions.
*
* Key Features:
* - Person profile creation and management
* - Group membership management with historical tracking
* - Age calculation and automatic updates
* - Duplicate detection and merging
* - Leadership role and job assignments
* - Permission-based access control
* - Family relationship management
* - Contact information synchronization
*
* Business Rules:
* - Persons can belong to multiple groups with different roles
* - Family relationships sync contact information automatically
* - Age is calculated from birth date and updated periodically
* - Duplicate detection uses phonetic matching
* - Historical data tracks all membership and role changes
* - Permissions are hierarchical based on organizational structure
*
* @requires express - Web framework for routing
* @requires ../utils/authChecks - Authentication and authorization utilities
* @requires ../utils/requestLogger - Request logging middleware
* @requires ./person/controller - Person business logic controller
*/
import express from 'express';
import { checkObjectAdmin, checkVisible, checkAdmin } from '../utils/authChecks.js';
import { requestUpdateLogger, readLogger } from '../utils/requestLogger.js';
import * as personController from './person/controller.js';
const api = express.Router();
/**
* @route GET /api/kpe20/person/ageUpdate
* @group Person Management
* @description Update age for all persons in the organization based on their birth dates
* This is typically run as a scheduled maintenance task
* @example
* GET /api/kpe20/person/ageUpdate
* Response: {"success": true, "updated": 150}
* @returns {Object} Response object
* @property {boolean} .success - Whether the operation was successful
* @property {number} .updated - Number of persons whose age was updated
*/
// @ts-ignore
api.get('/ageUpdate', checkAdmin, requestUpdateLogger, personController.ageUpdate);
// Update group membership for a person
/**
* @route POST /api/kpe20/person/:group/:UID
* @group Person Management
* @description Update a person's membership in a specific group
* @param {string} group - UUID of the group
* @param {string} UID - UUID of the person
* @param {object} body - Membership update data
* @param {string} [body.role] - New role in the group (member, leader, guest)
* @param {string} [body.startDate] - Membership start date (ISO format)
* @param {string} [body.endDate] - Membership end date (ISO format)
* @param {object} [body.additionalData] - Additional membership-specific data
* @example
* POST /api/kpe20/person/UUID-group-123/UUID-person-456
* Body: {"role": "leader", "startDate": "2024-01-01"}
* @returns {Object} Response object
* @property {boolean} .success - Whether the update was successful
* @property {object} .result - Updated membership information
*/
// @ts-ignore
api.post('/:group/:UID', requestUpdateLogger, personController.updateGroupMembership);
// Update person data
/**
* @route POST /api/kpe20/person/:UID
* @group Person Management
* @description Partially update a person's profile data by merging changes with existing data.
* This endpoint updates only the Member table and performs a partial merge of the provided
* data with existing data. Only changed fields need to be included in the request body.
*
* @param {string} UID - UUID of the person to update
* @param {object} body - Partial person data to merge (only include fields to update)
* @param {string} [body.firstName] - First name
* @param {string} [body.lastName] - Last name
* @param {string} [body.birthDate] - Birth date (YYYY-MM-DD format)
* @param {string} [body.gender] - Gender (M=Male, F=Female)
* @param {object[]} [body.address] - Contact addresses array
* @param {object[]} [body.phone] - Phone numbers array
* @param {object[]} [body.email] - Email addresses array
* @param {object[]} [body.accounts] - Account/banking information array
*
* @security Requires user to be an admin for the person being updated
*
* @example
* POST /api/kpe20/person/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
* Body: {"firstName": "John", "email": [{"type": "personal", "email": "john@example.com"}]}
*
* @returns {Object} Response object
* @property {boolean} .success - Whether the update was successful
* @property {object} .result - Complete updated person information
* @property {string} .result.UID - Person's UUID
* @property {object} .result.Data - Complete merged person data
*/
// @ts-ignore
api.post('/:UID', requestUpdateLogger, personController.updatePerson);
// Create or update person in group
/**
* @route PUT /api/kpe20/person/:group
* @group Person Management
* @description Create a new person or update an existing person in a specific group.
* This endpoint performs a complete object update, updating both ObjectBase and Member tables.
* If the person already exists, it updates all data and handles group membership changes.
* If the person doesn't exist, it creates a new person entry with a family record.
*
* @param {string} group - UUID of the group to add/update the person in
* @param {object} body - Complete person data
* @param {string} body.UID - UUID for the person (new or existing)
* @param {string} body.firstName - First name (required)
* @param {string} body.lastName - Last name (required)
* @param {string} body.birthDate - Birth date (YYYY-MM-DD format, required)
* @param {string} body.gender - Gender (M=Male, F=Female, required)
* @param {object[]} [body.address] - Contact addresses array
* @param {object[]} [body.phone] - Phone numbers array
* @param {object[]} [body.email] - Email addresses array
* @param {object[]} [body.accounts] - Account/banking information array
* @param {number} [body.stage] - Person's stage/level in hierarchy
* @param {number} [body.hierarchie] - Hierarchy level (inherited from group)
*
* @security Requires user to be an admin for the group
*
* @example
* PUT /api/kpe20/person/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
* Body: {
* "UID": "f1e2d3c4-b5a6-4978-8c9d-0e1f2a3b4c5d",
* "firstName": "Jane",
* "lastName": "Smith",
* "birthDate": "1995-03-15",
* "gender": "F"
* }
*
* @returns {Object} Response object
* @property {boolean} .success - Whether the operation was successful
* @property {object} .result - Created/updated person information
* @property {string} .result.UID - Person's UUID
* @property {string} .result.Type - Object type ('person')
* @property {object} .result.Data - Complete person data
* @property {boolean} .result.admin - Whether requesting user has admin rights
*/
// @ts-ignore
api.put('/:group', requestUpdateLogger, checkObjectAdmin, personController.createOrUpdatePerson);
// Get person details with optional related data
/**
* @route GET /api/kpe20/person/:UID
* @group Person Management
* @description Get detailed information about a person including profile, memberships, and related data
* @param {string} UID - UUID of the person to retrieve
* @param {string} [include] - Comma-separated list of related data to include (groups,family,jobs,history)
* @example
* GET /api/kpe20/person/UUID-person-123?include=groups,family
* @returns {Object} Response object
* @property {boolean} .success - Whether the request was successful
* @property {object} .result - Complete person data
* @property {string} .result.firstName - First name
* @property {string} .result.lastName - Last name
* @property {string} .result.birthDate - Birth date
* @property {number} .result.age - Calculated age
* @property {object[]} .result.groups - Group memberships (if included)
* @property {object} .result.family - Family information (if included)
* @property {object[]} .result.jobs - Leadership roles (if included)
*/
// @ts-ignore
api.get('/:UID', readLogger, personController.getPerson);
// Get person's group membership history
/**
* @route GET /api/kpe20/person/history/:UID
* @group Person Management
* @description Get the complete membership history for a person across all groups
* @param {string} UID - UUID of the person
* @param {string} [startDate] - Start date for history filter (ISO format)
* @param {string} [endDate] - End date for history filter (ISO format)
* @example
* GET /api/kpe20/person/history/UUID-person-123
* @returns {Object} Response object
* @property {boolean} .success - Whether the request was successful
* @property {object[]} .result - Array of historical membership records
* @property {string} .result[].groupName - Name of the group
* @property {string} .result[].role - Role in the group
* @property {string} .result[].startDate - Membership start date
* @property {string} .result[].endDate - Membership end date (if applicable)
*/
// @ts-ignore
api.get('/history/:UID', checkVisible, personController.personHistorie);
// Check admin rights for person
/**
* @route GET /api/kpe20/person/admin/:UID
* @group Person Management
* @description Check if the current user has admin privileges for the specified person
* @param {string} UID - UUID of the person to check
* @example
* GET /api/kpe20/person/admin/UUID-person-123
* Response: {"success": true, "result": true}
* @returns {Object} Response object
* @property {boolean} .success - Whether the request was successful
* @property {boolean} .result - Whether user has admin rights for this person
*/
// @ts-ignore
api.get('/admin/:UID', personController.personAdmin);
// Get person's leadership roles/jobs
/**
* @route GET /api/kpe20/person/leaders/:UID
* @group Person Management
* @description Get all leadership roles and jobs held by a person
* @param {string} UID - UUID of the person
* @example
* GET /api/kpe20/person/leaders/UUID-person-123
* @returns {Object} Response object
* @property {boolean} .success - Whether the request was successful
* @property {object[]} .result - Array of leadership roles
* @property {string} .result[].title - Job/office title
* @property {string} .result[].groupName - Group where the role is held
* @property {string} .result[].startDate - Role start date
* @property {string} .result[].endDate - Role end date (if applicable)
*/
// @ts-ignore
api.get('/leaders/:UID', checkVisible, personController.doCheckVisible);
// Find duplicate persons by name
/**
* @route GET /api/kpe20/person/duplicates/:firstName/:lastName
* @group Person Management
* @description Find potential duplicate persons using phonetic name matching
* @param {string} firstName - First name to search for
* @param {string} lastName - Last name to search for
* @param {string} [birthDate] - Optional birth date filter (ISO format)
* @example
* GET /api/kpe20/person/duplicates/John/Doe
* @returns {Object} Response object
* @property {boolean} .success - Whether the search was successful
* @property {object[]} .result - Array of potential duplicate persons
* @property {string} .result[].UID - Person UUID
* @property {string} .result[].firstName - First name
* @property {string} .result[].lastName - Last name
* @property {string} .result[].birthDate - Birth date
* @property {number} .result[].similarity - Similarity score (0-100)
*/
// @ts-ignore
api.get('/duplicates/:firstName/:lastName', personController.personDuplicates);
// Get person's jobs (ungrouped)
/**
* @route GET /api/kpe20/person/jobs/:UID
* @group Person Management
* @description Get all jobs/roles held by a person (ungrouped list)
* @param {string} UID - UUID of the person
* @example
* GET /api/kpe20/person/jobs/UUID-person-123
* @returns {Object} Response object
* @property {boolean} .success - Whether the request was successful
* @property {object[]} .result - Array of all jobs held by the person
* @property {string} .result[].title - Job title
* @property {string} .result[].groupName - Associated group name
* @property {string} .result[].startDate - Job start date
* @property {string} .result[].endDate - Job end date (if applicable)
*/
// @ts-ignore
api.get('/jobs/:UID', checkVisible, personController.jobgroups('visible', false));
// Get person's job groups (grouped by main group)
/**
* @route GET /api/kpe20/person/jobgroups/:UID
* @group Person Management
* @description Get person's jobs grouped by their main group
* @param {string} UID - UUID of the person
* @example
* GET /api/kpe20/person/jobgroups/UUID-person-123
* @returns {Object} Response object
* @property {boolean} .success - Whether the request was successful
* @property {object} .result - Jobs grouped by main group
* @property {object} .result.mainGroup - Primary group jobs
* @property {object[]} .result.otherGroups - Jobs in other groups
*/
// @ts-ignore
api.get('/jobgroups/:UID', checkVisible, personController.jobgroups('visible', true));
// Get person's changeable job groups
/**
* @route GET /api/kpe20/person/jobgroups/changeable/:UID
* @group Person Management
* @description Get person's jobs that can be modified by the current user
* @param {string} UID - UUID of the person
* @example
* GET /api/kpe20/person/jobgroups/changeable/UUID-person-123
* @returns {Object} Response object
* @property {boolean} .success - Whether the request was successful
* @property {object} .result - Jobs the user can modify
* @property {object[]} .result.canModify - Jobs user has permission to change
* @property {object[]} .result.readOnly - Jobs user can only view
*/
// @ts-ignore
api.get('/jobgroups/changeable/:UID', checkVisible, personController.jobgroups('changeable', true));
// Export helper functions for other modules
import { publishChangeEvent, updatePersonPartial } from './person/personHelpers.js';
export { publishChangeEvent, updatePersonPartial };
export const updatePerson = personController.updatePerson;
export const getPerson = personController.getPerson;
export const personAdmin = personController.personAdmin;
export const personHistorie = personController.personHistorie;
export const personDuplicates = personController.personDuplicates;
export const ageUpdate = personController.ageUpdate;
export default api;