import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; import { externalRest } from "../../lib/externalSupabase.ts"; import { mydb } from "../../lib/mySupabase.ts"; import { corsHeaders, jsonResponse, errorResponse } from "../../lib/utils.ts"; import { validateAuth, hasPermission } from "../../lib/auth.ts"; /** * POST /appointments/reschedule * Reagendamento inteligente de consulta * * Body: * { * appointment_id: uuid, * new_datetime?: string, * reason: string, * auto_suggest?: boolean * } * * Returns: * { * success: boolean, * appointment_id: uuid, * new_datetime: string, * notification_sent: boolean * } */ serve(async (req) => { if (req.method === "OPTIONS") { return new Response("ok", { headers: corsHeaders() }); } try { const auth = await validateAuth(req); if (!auth) { return errorResponse("Não autorizado", 401); } if (req.method !== "POST") { return errorResponse("Method not allowed", 405); } const body = await req.json(); const { appointment_id, new_datetime, reason, auto_suggest } = body; // Buscar agendamento original const appRes = await externalRest( `/rest/v1/appointments?id=eq.${appointment_id}`, "GET" ); if (appRes.status >= 400 || !appRes.data?.[0]) { return errorResponse("Agendamento não encontrado", 404); } const appointment = appRes.data[0]; // Verificar permissão (paciente ou staff) if (appointment.patient_id !== auth.userId && !hasPermission(auth.role, ["admin", "secretary"])) { return errorResponse("Sem permissão", 403); } // Validar regras de reagendamento const rulesRes = await mydb .from("reschedule_rules") .select("*") .eq("doctor_id", appointment.doctor_id); const rules = rulesRes.data?.[0]; if (rules) { const minAdvanceHours = rules.min_advance_hours || 24; const appointmentTime = new Date(appointment.date + "T" + appointment.time); const hoursUntilAppointment = (appointmentTime.getTime() - Date.now()) / (1000 * 60 * 60); if (hoursUntilAppointment < minAdvanceHours) { return errorResponse(`Reagendamento precisa ser feito com ${minAdvanceHours}h de antecedência`, 400); } } // Se novo horário não fornecido e auto_suggest=true, sugerir automaticamente let finalDateTime = new_datetime; if (!finalDateTime && auto_suggest) { const availRes = await externalRest( `/rest/v1/doctor_availability?doctor_id=eq.${appointment.doctor_id}&active=eq.true`, "GET" ); if (availRes.status >= 400 || !availRes.data?.[0]) { return errorResponse("Nenhuma disponibilidade encontrada", 400); } const nextAvailable = availRes.data[0]; finalDateTime = `${nextAvailable.date}T${nextAvailable.start_time}`; } if (!finalDateTime) { return errorResponse("Novo horário ou auto_suggest necessário", 400); } // Atualizar appointment no Supabase externo const updateRes = await externalRest( `/rest/v1/appointments?id=eq.${appointment_id}`, "PATCH", { date: finalDateTime.split("T")[0], time: finalDateTime.split("T")[1], status: "rescheduled", } ); if (updateRes.status >= 400) { return errorResponse("Falha ao reagendar", 500); } // Registrar histórico de alteração await mydb.from("appointment_history").insert({ appointment_id, field_changed: "datetime", old_value: `${appointment.date}T${appointment.time}`, new_value: finalDateTime, changed_by: auth.userId, change_reason: reason, }); // Registrar smart cancel log se aplicável await mydb.from("smart_cancel_log").insert({ appointment_id, rule_matched: "intelligent_reschedule", auto_rescheduled: true, new_appointment_id: appointment_id, }); // Criar notificação await mydb.from("notifications_queue").insert({ type: "email", recipient_id: appointment.patient_id, recipient_email: appointment.patient_email || null, payload: { subject: "Consulta Reagendada", body: `Sua consulta foi reagendada para ${finalDateTime}`, appointment_id, }, status: "pending", }); // Audit log await mydb.from("audit_log").insert({ user_id: auth.userId, action: "reschedule_appointment", target_type: "appointment", target_id: appointment_id, payload: { old_datetime: `${appointment.date}T${appointment.time}`, new_datetime: finalDateTime, reason }, }); return jsonResponse({ success: true, appointment_id, new_datetime: finalDateTime, notification_sent: true, }); } catch (error: unknown) { console.error("[reschedule]", error); const err = error as Error; return errorResponse(err.message, 500); } });