diff --git a/src/commands/messages/others/recordar.ts b/src/commands/messages/others/recordar.ts index 6976b04..be80290 100644 --- a/src/commands/messages/others/recordar.ts +++ b/src/commands/messages/others/recordar.ts @@ -13,6 +13,66 @@ function humanizeDate(d: Date) { return d.toLocaleString('es-ES', { timeZone: 'UTC', hour12: false }); } +function parseRelativeDelay(text: string): { when: Date, reminderText: string } | null { + const lower = text.toLowerCase(); + + // 1) "en menos de 1h" -> 59 minutos + let m = lower.match(/en\s+menos\s+de\s+1\s*h(ora(s)?)?/i); + if (m) { + const minutes = 59; + const when = new Date(Date.now() + minutes * 60 * 1000); + const reminderText = text.replace(m[0], '').trim() || text; + return { when, reminderText }; + } + + // 2) "en menos de X min" -> (X-1) minutos + m = lower.match(/en\s+menos\s+de\s+(\d+)\s*m(in(utos)?)?/i); + if (m) { + const minutes = Math.max(1, parseInt(m[1], 10) - 1); + const when = new Date(Date.now() + minutes * 60 * 1000); + const reminderText = text.replace(m[0], '').trim() || text; + return { when, reminderText }; + } + + // 3) "en X minutos" / "en Xm" + m = lower.match(/en\s+(\d+)\s*m(in(utos)?)?/i); + if (m) { + const minutes = Math.max(1, parseInt(m[1], 10)); + const when = new Date(Date.now() + minutes * 60 * 1000); + const reminderText = text.replace(m[0], '').trim() || text; + return { when, reminderText }; + } + + // 4) "en X horas" / "en Xh" + m = lower.match(/en\s+(\d+)\s*h(ora(s)?)?/i); + if (m) { + const hours = Math.max(1, parseInt(m[1], 10)); + const when = new Date(Date.now() + hours * 60 * 60 * 1000); + const reminderText = text.replace(m[0], '').trim() || text; + return { when, reminderText }; + } + + // 5) Post-fijo corto: "15m" o "45 min" al final + m = lower.match(/(\d+)\s*m(in(utos)?)?$/i); + if (m) { + const minutes = Math.max(1, parseInt(m[1], 10)); + const when = new Date(Date.now() + minutes * 60 * 1000); + const reminderText = text.slice(0, m.index).trim() || text; + return { when, reminderText }; + } + + // 6) Post-fijo corto: "1h" o "2 horas" al final + m = lower.match(/(\d+)\s*h(ora(s)?)?$/i); + if (m) { + const hours = Math.max(1, parseInt(m[1], 10)); + const when = new Date(Date.now() + hours * 60 * 60 * 1000); + const reminderText = text.slice(0, m.index).trim() || text; + return { when, reminderText }; + } + + return null; +} + export const command: CommandMessage = { name: 'recordar', type: 'message', @@ -32,39 +92,46 @@ export const command: CommandMessage = { return; } - // Parsear en español, forzando fechas futuras cuando sea ambiguo - const ref = new Date(); - const results = chrono.es.parse(text, ref, { forwardDate: true }); - if (!results.length) { - await message.reply('❌ No pude entender cuándo. Intenta algo como: "mañana 9am", "el miércoles 17:00", "en 2 horas".'); - return; - } - - const r = results[0]; - const when = r.date(); - - if (!when || isNaN(when.getTime())) { - await message.reply('❌ La fecha/hora no es válida.'); - return; - } - - // Evitar fechas pasadas - if (when.getTime() <= Date.now()) { - await message.reply('❌ La fecha/hora ya pasó. Especifica una fecha futura.'); - return; - } - - // Extraer el texto del recordatorio eliminando el fragmento reconocido de fecha - const matched = r.text || ''; + // 1) Soporte rápido para tiempos relativos: "en 10 minutos", "15m", "1h", "en menos de 1h" + const rel = parseRelativeDelay(text); + let when: Date | null = null; let reminderText = text; - if (matched) { - const idx = text.toLowerCase().indexOf(matched.toLowerCase()); - if (idx >= 0) { - reminderText = (text.slice(0, idx) + text.slice(idx + matched.length)).trim(); + if (rel) { + when = rel.when; + reminderText = rel.reminderText; + } + + // 2) Si no hubo match relativo, usar parser natural (chrono) en español + if (!when) { + const ref = new Date(); + const results = chrono.es.parse(text, ref, { forwardDate: true }); + if (!results.length) { + await message.reply('❌ No pude entender cuándo. Intenta algo como: "en 10 minutos", "mañana 9am", "el miércoles 17:00".'); + return; + } + const r = results[0]; + when = r.date(); + + if (!when || isNaN(when.getTime())) { + await message.reply('❌ La fecha/hora no es válida.'); + return; + } + + // Extraer el texto del recordatorio eliminando el fragmento reconocido de fecha + const matched = r.text || ''; + if (matched) { + const idx = text.toLowerCase().indexOf(matched.toLowerCase()); + if (idx >= 0) { + reminderText = (text.slice(0, idx) + text.slice(idx + matched.length)).trim() || text; + } } } - // Si quedó vacío, usar el texto completo - if (!reminderText) reminderText = text; + + // Validaciones de futuro y límites mínimos + if (when.getTime() <= Date.now() + 20 * 1000) { // al menos 20s al futuro + await message.reply('❌ Especifica un tiempo al futuro (al menos ~20 segundos).'); + return; + } // Guardar en Appwrite const iso = new Date(when.getTime()).toISOString(); @@ -86,4 +153,3 @@ export const command: CommandMessage = { await message.reply(`✅ Recordatorio guardado para: ${whenHuman} UTC\nMensaje: ${reminderText}`); } }; -