/* |-------------------------------------------------------------------------- | Agência PSI |-------------------------------------------------------------------------- | Arquivo: src/composables/useConversationNotes.js | Data: 2026-04-21 | | Notas internas por thread de conversa. Carregadas sob demanda quando o | drawer da conversa abre. |-------------------------------------------------------------------------- */ import { ref, computed } from 'vue'; import { supabase } from '@/lib/supabase/client'; import { useTenantStore } from '@/stores/tenantStore'; function sanitizeBody(raw) { if (typeof raw !== 'string') return ''; return raw.trim().slice(0, 4000); } export function useConversationNotes() { const tenantStore = useTenantStore(); const notes = ref([]); const loading = ref(false); const saving = ref(false); const error = ref(null); const count = computed(() => notes.value.length); async function load(threadKey) { if (!threadKey) { notes.value = []; return; } const tenantId = tenantStore.activeTenantId; if (!tenantId) { notes.value = []; return; } loading.value = true; error.value = null; try { const { data, error: err } = await supabase .from('conversation_notes') .select('id, thread_key, patient_id, contact_number, body, created_by, created_at, updated_at') .eq('tenant_id', tenantId) .eq('thread_key', threadKey) .is('deleted_at', null) .order('created_at', { ascending: false }); if (err) throw err; // Busca nomes dos criadores (1 query só) const rows = data || []; const userIds = [...new Set(rows.map((r) => r.created_by).filter(Boolean))]; let nameMap = {}; if (userIds.length) { const { data: users } = await supabase .from('profiles') .select('id, full_name') .in('id', userIds); nameMap = Object.fromEntries((users || []).map((u) => [u.id, u.full_name || ''])); } notes.value = rows.map((r) => ({ ...r, _author_name: nameMap[r.created_by] || null })); } catch (e) { error.value = e?.message || 'Falha ao carregar notas'; notes.value = []; } finally { loading.value = false; } } async function create({ threadKey, patientId = null, contactNumber = null, body }) { const tenantId = tenantStore.activeTenantId; const clean = sanitizeBody(body); if (!tenantId || !threadKey || !clean) return { ok: false, error: 'invalid_params' }; saving.value = true; try { const { data: authData } = await supabase.auth.getUser(); const userId = authData?.user?.id; if (!userId) return { ok: false, error: 'not_authenticated' }; const { data, error: err } = await supabase .from('conversation_notes') .insert({ tenant_id: tenantId, thread_key: threadKey, patient_id: patientId, contact_number: contactNumber, body: clean, created_by: userId }) .select('id, thread_key, patient_id, contact_number, body, created_by, created_at, updated_at') .single(); if (err) throw err; // Prepend (mais recente primeiro) notes.value = [{ ...data, _author_name: null }, ...notes.value]; // Recarrega o display_name do autor novo const { data: u } = await supabase .from('profiles') .select('full_name') .eq('id', data.created_by) .maybeSingle(); if (u?.full_name) { const item = notes.value.find((n) => n.id === data.id); if (item) item._author_name = u.full_name; } return { ok: true, note: data }; } catch (e) { return { ok: false, error: e?.message || 'insert_failed' }; } finally { saving.value = false; } } async function update(id, body) { const clean = sanitizeBody(body); if (!id || !clean) return { ok: false, error: 'invalid_params' }; saving.value = true; try { const { error: err } = await supabase .from('conversation_notes') .update({ body: clean }) .eq('id', id); if (err) throw err; const item = notes.value.find((n) => n.id === id); if (item) { item.body = clean; item.updated_at = new Date().toISOString(); } return { ok: true }; } catch (e) { return { ok: false, error: e?.message || 'update_failed' }; } finally { saving.value = false; } } async function remove(id) { if (!id) return { ok: false, error: 'invalid_id' }; saving.value = true; try { const { error: err } = await supabase .from('conversation_notes') .update({ deleted_at: new Date().toISOString() }) .eq('id', id); if (err) throw err; notes.value = notes.value.filter((n) => n.id !== id); return { ok: true }; } catch (e) { return { ok: false, error: e?.message || 'delete_failed' }; } finally { saving.value = false; } } function clear() { notes.value = []; error.value = null; } return { notes, count, loading, saving, error, load, create, update, remove, clear }; }