import { db, encryptedDb } from '../config/secureDatabase' import { Employee } from '@skillmate/shared' import { v4 as uuidv4 } from 'uuid' export interface EmployeeInput { firstName: string lastName: string employeeNumber?: string | null photo?: string | null position?: string department: string email: string phone?: string | null mobile?: string | null office?: string | null availability?: string clearance?: { level?: string; validUntil?: string | Date | null; issuedDate?: string | Date | null } | null skills?: Array<{ id: string; level?: any; verified?: boolean; verifiedBy?: string | null; verifiedDate?: string | Date | null }> languages?: Array<{ code: string; level: string }> specializations?: string[] } export function getAllWithDetails(): Employee[] { const emps = (encryptedDb.getAllEmployees() as any[]) || [] if (emps.length === 0) return [] const ids = emps.map((e: any) => e.id) const placeholders = ids.map(() => '?').join(',') // Batch fetch related data const skillsRows = db.prepare(` SELECT es.employee_id, s.id, s.name, s.category, es.level, es.verified, es.verified_by, es.verified_date FROM employee_skills es JOIN skills s ON es.skill_id = s.id WHERE es.employee_id IN (${placeholders}) `).all(...ids) as any[] const langRows = db.prepare(` SELECT employee_id, language, proficiency, certified, certificate_type, is_native, can_interpret FROM language_skills WHERE employee_id IN (${placeholders}) `).all(...ids) as any[] const specRows = db.prepare(` SELECT employee_id, name FROM specializations WHERE employee_id IN (${placeholders}) `).all(...ids) as any[] const skillsByEmp = new Map() for (const r of skillsRows) { if (!skillsByEmp.has(r.employee_id)) skillsByEmp.set(r.employee_id, []) skillsByEmp.get(r.employee_id)!.push(r) } const langsByEmp = new Map() for (const r of langRows) { if (!langsByEmp.has(r.employee_id)) langsByEmp.set(r.employee_id, []) langsByEmp.get(r.employee_id)!.push(r) } const specsByEmp = new Map() for (const r of specRows) { if (!specsByEmp.has(r.employee_id)) specsByEmp.set(r.employee_id, []) specsByEmp.get(r.employee_id)!.push(r.name) } const mapProf = (p: string): 'basic' | 'fluent' | 'native' | 'business' => { const m: Record = { A1: 'basic', A2: 'basic', B1: 'business', B2: 'business', C1: 'fluent', C2: 'fluent', Muttersprache: 'native', native: 'native', fluent: 'fluent', advanced: 'business', intermediate: 'business', basic: 'basic' } return m[p] || 'basic' } return emps.map((emp: any) => { const s = skillsByEmp.get(emp.id) || [] const l = langsByEmp.get(emp.id) || [] const sp = specsByEmp.get(emp.id) || [] return { id: emp.id, firstName: emp.first_name, lastName: emp.last_name, employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined, photo: emp.photo, position: emp.position, department: emp.department, email: emp.email, phone: emp.phone, mobile: emp.mobile, office: emp.office, availability: emp.availability, skills: s.map((r: any) => ({ id: r.id, name: r.name, category: r.category, level: r.level, verified: Boolean(r.verified), verifiedBy: r.verified_by, verifiedDate: r.verified_date ? new Date(r.verified_date) : undefined })), languages: l.map((r: any) => ({ code: r.language, level: mapProf(r.proficiency) })), clearance: emp.clearance_level && emp.clearance_valid_until && emp.clearance_issued_date ? { level: emp.clearance_level, validUntil: new Date(emp.clearance_valid_until), issuedDate: new Date(emp.clearance_issued_date) } : undefined, specializations: sp, createdAt: new Date(emp.created_at), updatedAt: new Date(emp.updated_at), createdBy: emp.created_by, updatedBy: emp.updated_by } as Employee }) } export function getByIdWithDetails(id: string): Employee | null { const emp = encryptedDb.getEmployee(id) as any if (!emp) return null return buildEmployeeWithDetails(emp) } function buildEmployeeWithDetails(emp: any): Employee { const skills = db.prepare(` SELECT s.id, s.name, s.category, es.level, es.verified, es.verified_by, es.verified_date FROM employee_skills es JOIN skills s ON es.skill_id = s.id WHERE es.employee_id = ? `).all(emp.id) const languages = db.prepare(` SELECT language, proficiency, certified, certificate_type, is_native, can_interpret FROM language_skills WHERE employee_id = ? `).all(emp.id) const specializations = db.prepare(` SELECT name FROM specializations WHERE employee_id = ? `).all(emp.id).map((s: any) => s.name) const mapProf = (p: string): 'basic' | 'fluent' | 'native' | 'business' => { const m: Record = { A1: 'basic', A2: 'basic', B1: 'business', B2: 'business', C1: 'fluent', C2: 'fluent', Muttersprache: 'native', native: 'native', fluent: 'fluent', advanced: 'business', intermediate: 'business', basic: 'basic' } return m[p] || 'basic' } return { id: emp.id, firstName: emp.first_name, lastName: emp.last_name, employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined, photo: emp.photo, position: emp.position, department: emp.department, email: emp.email, phone: emp.phone, mobile: emp.mobile, office: emp.office, availability: emp.availability, skills: skills.map((s: any) => ({ id: s.id, name: s.name, category: s.category, level: s.level, verified: Boolean(s.verified), verifiedBy: s.verified_by, verifiedDate: s.verified_date ? new Date(s.verified_date) : undefined })), languages: languages.map((l: any) => ({ code: l.language, level: mapProf(l.proficiency) })), clearance: emp.clearance_level && emp.clearance_valid_until && emp.clearance_issued_date ? { level: emp.clearance_level, validUntil: new Date(emp.clearance_valid_until), issuedDate: new Date(emp.clearance_issued_date) } : undefined, specializations, createdAt: new Date(emp.created_at), updatedAt: new Date(emp.updated_at), createdBy: emp.created_by, updatedBy: emp.updated_by } } export function createEmployee(input: EmployeeInput, actorUserId: string): { id: string } { const now = new Date().toISOString() const employeeId = uuidv4() const position = input.position || 'Teammitglied' const phone = input.phone || 'Nicht angegeben' const availability = input.availability || 'available' const employeeNumber = input.employeeNumber || `EMP${Date.now()}` const tx = db.transaction(() => { // Uniqueness check for employee number const existingEmployee = db.prepare('SELECT id FROM employees WHERE employee_number = ?').get(employeeNumber) if (existingEmployee) { const err: any = new Error('Employee number already exists') err.statusCode = 409 throw err } encryptedDb.insertEmployee({ id: employeeId, first_name: input.firstName, last_name: input.lastName, employee_number: employeeNumber, photo: input.photo || null, position, department: input.department, email: input.email, phone, mobile: input.mobile || null, office: input.office || null, availability, clearance_level: input.clearance?.level || null, clearance_valid_until: input.clearance?.validUntil || null, clearance_issued_date: input.clearance?.issuedDate || null, created_at: now, updated_at: now, created_by: actorUserId, updated_by: actorUserId, }) if (input.skills && input.skills.length > 0) { const stmt = db.prepare(` INSERT INTO employee_skills (employee_id, skill_id, level, verified, verified_by, verified_date) VALUES (?, ?, ?, ?, ?, ?) `) const checkSkillExists = db.prepare('SELECT id FROM skills WHERE id = ?') for (const s of input.skills) { const exists = checkSkillExists.get(s.id) if (!exists) continue stmt.run(employeeId, s.id, typeof s.level === 'number' ? s.level : (parseInt(String(s.level)) || null), s.verified ? 1 : 0, s.verifiedBy || null, s.verifiedDate || null) } } if (input.languages && input.languages.length > 0) { const stmt = db.prepare(` INSERT INTO language_skills (id, employee_id, language, proficiency, certified, certificate_type, is_native, can_interpret) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `) for (const l of input.languages) { stmt.run(uuidv4(), employeeId, l.code, l.level, 0, null, 0, 0) } } if (input.specializations && input.specializations.length > 0) { const stmt = db.prepare('INSERT INTO specializations (id, employee_id, name) VALUES (?, ?, ?)') for (const name of input.specializations) { stmt.run(uuidv4(), employeeId, name) } } }) tx() return { id: employeeId } } export function updateEmployee(id: string, input: EmployeeInput, actorUserId: string) { const now = new Date().toISOString() const tx = db.transaction(() => { const existing = db.prepare('SELECT id FROM employees WHERE id = ?').get(id) if (!existing) { const err: any = new Error('Employee not found') err.statusCode = 404 throw err } db.prepare(` UPDATE employees SET first_name = ?, last_name = ?, position = ?, department = ?, email = ?, email_hash = ?, phone = ?, phone_hash = ?, mobile = ?, office = ?, availability = ?, clearance_level = ?, clearance_valid_until = ?, clearance_issued_date = ?, updated_at = ?, updated_by = ? WHERE id = ? `).run( input.firstName, input.lastName, input.position || 'Teammitglied', input.department, // encryption handled in secure db layer caller; here store encrypted values already in input? Route prepares with FieldEncryption input.email, // already encrypted by route layer null, // email_hash set by route if needed input.phone || '', null, // phone_hash set by route if needed input.mobile || null, input.office || null, input.availability || 'available', input.clearance?.level || null, input.clearance?.validUntil || null, input.clearance?.issuedDate || null, now, actorUserId, id ) if (input.skills) { db.prepare('DELETE FROM employee_skills WHERE employee_id = ?').run(id) if (input.skills.length > 0) { const insert = db.prepare(` INSERT INTO employee_skills (employee_id, skill_id, level, verified, verified_by, verified_date) VALUES (?, ?, ?, ?, ?, ?) `) const checkSkillExists = db.prepare('SELECT id FROM skills WHERE id = ?') for (const s of input.skills) { const exists = checkSkillExists.get(s.id) if (!exists) continue insert.run( id, s.id, typeof s.level === 'number' ? s.level : (parseInt(String(s.level)) || null), s.verified ? 1 : 0, s.verifiedBy || null, s.verifiedDate || null ) } } } }) tx() } export function deleteEmployee(id: string) { const tx = db.transaction(() => { const existing = db.prepare('SELECT id FROM employees WHERE id = ?').get(id) if (!existing) { const err: any = new Error('Employee not found') err.statusCode = 404 throw err } db.prepare('DELETE FROM employee_skills WHERE employee_id = ?').run(id) db.prepare('DELETE FROM language_skills WHERE employee_id = ?').run(id) db.prepare('DELETE FROM specializations WHERE employee_id = ?').run(id) db.prepare('DELETE FROM employees WHERE id = ?').run(id) }) tx() }