import { Router } from "express"; import { db } from "../db.ts"; import type { AuthedRequest } from "../lib/auth.ts"; import { err, ownerOnly } from "../lib/auth.ts"; import type { EmployeeStats } from "../../shared/types.ts"; export const employeesRouter = Router(); function attachServices(emp: any) { const ids = db .prepare(`SELECT service_id FROM employee_services WHERE employee_id = ?`) .all(emp.id) .map((r: any) => r.service_id); emp.service_ids = ids; return emp; } function computeStats(employeeId: number, businessId: number): EmployeeStats { const completed = db .prepare( `SELECT COUNT(*) c, COALESCE(SUM(price),0) s FROM appointments WHERE employee_id = ? AND status = 'completed'` ) .get(employeeId) as { c: number; s: number }; const total = db .prepare(`SELECT COUNT(*) c FROM appointments WHERE employee_id = ?`) .get(employeeId) as { c: number }; const rating = db .prepare( `SELECT COALESCE((SELECT AVG(rating) FROM reviews WHERE employee_id = ?), (SELECT rating FROM employees WHERE id = ?)) r` ) .get(employeeId, employeeId) as { r: number }; const topEmp = db .prepare( `SELECT COUNT(*) c FROM appointments WHERE employee_id = ? AND status IN ('completed','scheduled')` ) .get(employeeId) as { c: number }; const totalBiz = db .prepare( `SELECT COUNT(*) c FROM appointments WHERE business_id = ? AND status IN ('completed','scheduled')` ) .get(businessId) as { c: number }; const utilization = totalBiz.c > 0 ? Math.round((topEmp.c / totalBiz.c) * 100) : 0; return { appointments_total: total.c, appointments_completed: completed.c, revenue_total: completed.s, avg_rating: Math.round((rating.r ?? 5) * 10) / 10, utilization_pct: utilization, }; } employeesRouter.get("/", (req: AuthedRequest, res) => { const rows = db .prepare(`SELECT * FROM employees WHERE business_id = ? ORDER BY active DESC, name`) .all(req.user!.business_id) as any[]; const out = rows.map((r) => { attachServices(r); r.stats = computeStats(r.id, req.user!.business_id as number); return r; }); res.json({ employees: out }); }); employeesRouter.get("/:id", (req: AuthedRequest, res) => { const emp = db.prepare(`SELECT * FROM employees WHERE id = ? AND business_id = ?`).get( Number(req.params.id), req.user!.business_id ) as any; if (!emp) return err(res, 404, "Empleado no encontrado"); attachServices(emp); emp.stats = computeStats(emp.id, req.user!.business_id as number); res.json({ employee: emp }); }); employeesRouter.post("/", ownerOnly, (req: AuthedRequest, res) => { const { name, role, email, phone, color, service_ids } = req.body ?? {}; if (!name) return err(res, 400, "El nombre es obligatorio"); const r = db .prepare( `INSERT INTO employees (business_id, name, role, email, phone, color) VALUES (?, ?, ?, ?, ?, ?) RETURNING *` ) .get( req.user!.business_id, name, role || "Especialista", email || null, phone || null, color || "#3b66ff" ) as any; if (Array.isArray(service_ids)) { const ins = db.prepare(`INSERT OR IGNORE INTO employee_services (employee_id, service_id) VALUES (?, ?)`); for (const sid of service_ids) ins.run(r.id, Number(sid)); } attachServices(r); r.stats = computeStats(r.id, req.user!.business_id as number); res.status(201).json({ employee: r }); }); employeesRouter.patch("/:id", ownerOnly, (req: AuthedRequest, res) => { const id = Number(req.params.id); const existing = db .prepare(`SELECT * FROM employees WHERE id = ? AND business_id = ?`) .get(id, req.user!.business_id as number) as any; if (!existing) return err(res, 404, "Empleado no encontrado"); const { name, role, email, phone, color, active, service_ids } = req.body ?? {}; const merged = { name: name ?? existing.name, role: role ?? existing.role, email: email ?? existing.email, phone: phone ?? existing.phone, color: color ?? existing.color, active: active === undefined ? existing.active : active ? 1 : 0, }; db.prepare( `UPDATE employees SET name = ?, role = ?, email = ?, phone = ?, color = ?, active = ? WHERE id = ?` ).run(merged.name, merged.role, merged.email, merged.phone, merged.color, merged.active, id); if (Array.isArray(service_ids)) { db.prepare(`DELETE FROM employee_services WHERE employee_id = ?`).run(id); const ins = db.prepare(`INSERT OR IGNORE INTO employee_services (employee_id, service_id) VALUES (?, ?)`); for (const sid of service_ids) ins.run(id, Number(sid)); } const updated = db.prepare(`SELECT * FROM employees WHERE id = ?`).get(id) as any; attachServices(updated); updated.stats = computeStats(updated.id, req.user!.business_id as number); res.json({ employee: updated }); }); employeesRouter.delete("/:id", ownerOnly, (req: AuthedRequest, res) => { const id = Number(req.params.id); const existing = db .prepare(`SELECT id FROM employees WHERE id = ? AND business_id = ?`) .get(id, req.user!.business_id as number); if (!existing) return err(res, 404, "Empleado no encontrado"); db.prepare(`DELETE FROM employees WHERE id = ?`).run(id); res.json({ ok: true }); });