import 'dart:convert'; import '../modelos/emisora.dart'; import '../modelos/grupo_favoritos.dart'; import '../modelos/preset_ecualizador.dart'; /// Owns the backup (export/import) JSON serialization (S4-R4). /// /// The v2 envelope produced here is byte-compatible with the legacy format /// previously assembled inline by `EstadoRadio.exportarConfig` and /// pretty-printed by `pantalla_ajustes.dart`, so existing exports keep /// round-tripping. State APPLICATION (writing favorites, EQ, alarms back /// into the app) stays in `EstadoRadio.importarConfig` — this service only /// owns serialization, parsing and the envelope shape. class ServicioExportImport { const ServicioExportImport(); /// Current backup schema version (v2 — full portability). static const int versionActual = 2; /// Builds the v2 export envelope. Key set and semantics must stay exactly /// as the legacy inline export so old backups remain importable: /// the `alarmas` block is the RAW JSON map persisted by ServicioAlarmas /// and passes through untouched (no re-parsing here). Map construirExportacion({ required List gruposFavoritos, required List favoritos, required List emisorasCustom, required PresetEcualizador presetPrincipal, required Map presetsPorEmisora, required Map? alarmas, required String? emisoraPreferidaUuid, required String ordenListas, required List timerSuenoPresetsSegundos, DateTime? exportadoEn, }) { return { 'version': versionActual, 'exportedAt': (exportadoEn ?? DateTime.now()).toIso8601String(), // Favorites + groups (preserves grupo_id assignments per station). // The protected "sin asignar" group is implicit and never exported. 'gruposFavoritos': gruposFavoritos .where((g) => !g.esSinAsignar) .map((g) => g.toMap()) .toList(), 'favoritos': favoritos.map((e) => e.toMap()).toList(), // Custom stations. 'emisorasCustom': emisorasCustom.map((e) => e.toMap()).toList(), // Equalizer. 'presetPrincipalEcualizador': presetPrincipal.toJson(), 'presetsEcualizador': presetsPorEmisora.map( (uuid, preset) => MapEntry(uuid, preset.toJson()), ), // Full alarm block (alarms + vacations + exceptions) — raw passthrough. 'alarmas': alarmas, // User preferences. 'emisoraPreferidaUuid': emisoraPreferidaUuid, 'ordenListas': ordenListas, 'timerSuenoPresetsSegundos': timerSuenoPresetsSegundos, }; } /// Serializes an export envelope to pretty-printed JSON (same formatting /// the legacy export shared as a file). String exportar(Map config) => const JsonEncoder.withIndent(' ').convert(config); /// Parses a backup JSON string. Returns `null` on malformed input or when /// the document is not a JSON object — graceful, never throws (S4-R4). Map? importar(String raw) { try { final decoded = jsonDecode(raw); if (decoded is! Map) return null; return Map.from(decoded); } on FormatException { return null; } } }