students = $students; $this->templates = $templates; $this->families = $families; $this->previewService = $previewService; $this->sendService = $sendService; } public function options(): JsonResponse { return response()->json([ 'ok' => true, 'students' => $this->students->listStudents(), 'templates' => $this->templates->listActiveTemplates(), ]); } public function families(int $studentId): JsonResponse { return response()->json([ 'ok' => true, 'data' => $this->families->familiesForStudent($studentId), ]); } public function guardians(int $familyId): JsonResponse { return response()->json([ 'ok' => true, 'data' => $this->families->guardiansForFamily($familyId), ]); } public function preview(Request $request): JsonResponse { $templateKey = (string) $request->input('template_key', ''); $studentId = (int) $request->input('student_id', 0); $familyId = (int) $request->input('family_id', 0); $vars = $this->normalizeArray($request->input('vars', [])); if ($templateKey === '' || $studentId <= 0 || $familyId <= 0) { return response()->json([ 'ok' => false, 'message' => 'template_key, student_id, and family_id are required.', ], 422); } $teacherName = $this->resolveTeacherName(); $result = $this->previewService->buildPreview($templateKey, $studentId, $familyId, $vars, $teacherName); if (! $result['ok']) { return response()->json([ 'ok' => false, 'message' => $result['message'] ?? 'Preview failed.', ], $result['status'] ?? 400); } return response()->json([ 'ok' => true, 'subject' => $result['subject'], 'html' => $result['html'], ]); } public function send(Request $request): JsonResponse { $studentId = (int) $request->input('student_id', 0); $familyId = (int) $request->input('family_id', 0); $templateKey = (string) $request->input('template_key', ''); $subject = (string) $request->input('subject', ''); $body = (string) $request->input('body', ''); $recipients = $this->normalizeArray($request->input('recipients', [])); $cc = $this->normalizeArray($request->input('cc', [])); $bcc = $this->normalizeArray($request->input('bcc', [])); if ($studentId <= 0 || $familyId <= 0 || $templateKey === '' || $subject === '' || $body === '') { return response()->json([ 'ok' => false, 'message' => 'student_id, family_id, template_key, subject, and body are required.', ], 422); } if (empty($recipients)) { return response()->json([ 'ok' => false, 'message' => 'At least one recipient is required.', ], 422); } $student = $this->students->getStudentBasic($studentId); if (! $student) { return response()->json([ 'ok' => false, 'message' => 'Student not found.', ], 404); } $senderId = $this->authenticatedUserIdOrUnauthorized(); if ($senderId instanceof JsonResponse) { return $senderId; } $result = $this->sendService->send([ 'student_id' => $studentId, 'family_id' => $familyId, 'template_key' => $templateKey, 'subject' => $subject, 'body' => $body, 'recipients' => $recipients, 'cc' => $cc, 'bcc' => $bcc, 'student_name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), 'sent_by' => $senderId, ]); if (! $result['ok']) { return response()->json([ 'ok' => false, 'message' => 'Failed to send email.', 'error' => $result['error'], ], 500); } return response()->json([ 'ok' => true, 'message' => 'Email sent successfully.', ]); } private function normalizeArray($value): array { if (is_array($value)) { return $value; } if (is_string($value) && $value !== '') { $decoded = json_decode($value, true); if (is_array($decoded)) { return $decoded; } } return []; } private function resolveTeacherName(): string { $user = auth()->user(); if ($user) { $name = trim(($user->firstname ?? '').' '.($user->lastname ?? '')); return $name !== '' ? $name : 'Teacher'; } return 'Teacher'; } private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); if ($userId <= 0) { return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401); } return $userId; } }