import { getSettings, upsertSettings, getStoreConfig } from "../db/settingsRepo.js"; const VALID_DAYS = ["lun", "mar", "mie", "jue", "vie", "sab", "dom"]; function defaultPickupSchedule() { const days = ["lun", "mar", "mie", "jue", "vie", "sab"]; const pickup = {}; for (const d of days) pickup[d] = { start: "08:00", end: "20:00" }; return { pickup }; } export async function handleGetSettings({ tenantId }) { const settings = await getSettings({ tenantId }); if (!settings) { return { store_name: "Mi Negocio", bot_name: "Piaf", store_address: "", store_phone: "", pickup_enabled: true, pickup_days: "lun,mar,mie,jue,vie,sab", pickup_hours_start: "08:00", pickup_hours_end: "20:00", schedule: defaultPickupSchedule(), delivery_zones: {}, is_default: true, }; } // Si schedule está vacío pero tenemos los campos legacy de pickup, generar // schedule.pickup para que la UI pueda editar el grid por día. let schedule = settings.schedule; if (!schedule || !schedule.pickup || !Object.keys(schedule.pickup).length) { schedule = buildPickupScheduleFromLegacy(settings); } return { ...settings, pickup_hours_start: settings.pickup_hours_start?.slice(0, 5) || "08:00", pickup_hours_end: settings.pickup_hours_end?.slice(0, 5) || "20:00", schedule, delivery_zones: settings.delivery_zones || {}, is_default: false, }; } function buildPickupScheduleFromLegacy(settings) { const out = { pickup: {} }; if (settings?.pickup_enabled && settings?.pickup_days) { const days = settings.pickup_days.split(",").map((d) => d.trim()); const start = settings.pickup_hours_start?.slice(0, 5) || "08:00"; const end = settings.pickup_hours_end?.slice(0, 5) || "20:00"; for (const day of days) { if (VALID_DAYS.includes(day)) out.pickup[day] = { start, end }; } } return out; } function validateSchedule(schedule) { if (!schedule || typeof schedule !== "object") return; const timeRegex = /^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/; const pickup = schedule.pickup; if (!pickup || typeof pickup !== "object") return; for (const [day, slot] of Object.entries(pickup)) { if (!VALID_DAYS.includes(day)) throw new Error(`Invalid day in schedule.pickup: ${day}`); if (slot === null) continue; if (typeof slot !== "object" || !slot.start || !slot.end) { throw new Error(`Invalid slot format for pickup.${day}`); } if (!timeRegex.test(slot.start)) throw new Error(`Invalid start time for pickup.${day}: ${slot.start}`); if (!timeRegex.test(slot.end)) throw new Error(`Invalid end time for pickup.${day}: ${slot.end}`); } } function syncPickupLegacyFromSchedule(settings) { const pickup = settings?.schedule?.pickup; if (!pickup) return; const days = Object.keys(pickup).filter((d) => pickup[d] && pickup[d].start && pickup[d].end); days.sort((a, b) => VALID_DAYS.indexOf(a) - VALID_DAYS.indexOf(b)); if (days.length) { settings.pickup_days = days.join(","); const first = pickup[days[0]]; settings.pickup_hours_start = first.start; settings.pickup_hours_end = first.end; } else { settings.pickup_days = ""; } } function validateDeliveryZones(dz) { if (!dz || typeof dz !== "object") return; if (dz.zones && !Array.isArray(dz.zones)) { throw new Error("delivery_zones.zones must be an array"); } for (const z of dz.zones || []) { if (!z?.id || !z?.name) throw new Error("Each zone needs id + name"); if (z.polygon && (z.polygon.type !== "Polygon" || !Array.isArray(z.polygon.coordinates))) { throw new Error(`Invalid polygon GeoJSON for zone ${z.id}`); } if (Array.isArray(z.delivery_days)) { for (const d of z.delivery_days) { if (!VALID_DAYS.includes(d)) throw new Error(`Invalid delivery day in zone ${z.id}: ${d}`); } } } } export async function handleSaveSettings({ tenantId, settings }) { if (!settings.store_name?.trim()) throw new Error("store_name is required"); if (!settings.bot_name?.trim()) throw new Error("bot_name is required"); if (settings.schedule) { validateSchedule(settings.schedule); syncPickupLegacyFromSchedule(settings); } if (settings.delivery_zones) { validateDeliveryZones(settings.delivery_zones); } if (settings.pickup_days) { const days = settings.pickup_days.split(",").map((d) => d.trim().toLowerCase()); for (const d of days) { if (!VALID_DAYS.includes(d)) throw new Error(`Invalid pickup day: ${d}`); } settings.pickup_days = days.join(","); } const timeRegex = /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/; if (settings.pickup_hours_start && !timeRegex.test(settings.pickup_hours_start)) { throw new Error("Invalid pickup_hours_start format (use HH:MM)"); } if (settings.pickup_hours_end && !timeRegex.test(settings.pickup_hours_end)) { throw new Error("Invalid pickup_hours_end format (use HH:MM)"); } const result = await upsertSettings({ tenantId, settings }); return { ok: true, settings: { ...result, pickup_hours_start: result.pickup_hours_start?.slice(0, 5), pickup_hours_end: result.pickup_hours_end?.slice(0, 5), delivery_zones: result.delivery_zones || {}, }, message: "Configuración guardada correctamente", }; } export async function handleGetStoreConfig({ tenantId }) { return await getStoreConfig({ tenantId }); }