import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/modelos/alarma_musical.dart'; import 'package:pluriwave/servicios/servicio_alarmas.dart'; import 'package:pluriwave/servicios/servicio_alarmas_android.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUp(() { SharedPreferences.setMockInitialValues({}); }); group('ServicioAlarmas.posponerEjecucion (ancla unificada)', () { Future servicioConAlarma(DateTime ahora) async { final servicio = ServicioAlarmas(reloj: () => ahora); await servicio.guardarAlarma( const AlarmaMusical( id: 'p1', nombre: 'Snooze', hora: 8, minuto: 30, tipoProgramacion: TipoProgramacionAlarma.diaria, diasSemana: [], ), ); return servicio; } test('ancla en ejecucion + minutos cuando el objetivo es futuro', () async { final servicio = await servicioConAlarma(DateTime(2026, 6, 11, 8, 0)); final config = await servicio.posponerEjecucion( 'p1', DateTime(2026, 6, 11, 8, 30), 10, ); final alarma = config.alarmas.single; expect(alarma.snoozeHasta, DateTime(2026, 6, 11, 8, 40)); expect(alarma.snoozeOrigen, DateTime(2026, 6, 11, 8, 30)); final recargada = await servicio.cargar(); expect( recargada.alarmas.single.snoozeHasta, DateTime(2026, 6, 11, 8, 40), reason: 'el snooze debe quedar persistido', ); }); test('clava a ahora + minutos cuando el objetivo ya paso', () async { final servicio = await servicioConAlarma(DateTime(2026, 6, 11, 9, 0)); final config = await servicio.posponerEjecucion( 'p1', DateTime(2026, 6, 11, 8, 30), 5, ); expect(config.alarmas.single.snoozeHasta, DateTime(2026, 6, 11, 9, 5)); }); test('respeta minutos personalizados fuera de 3/5/10', () async { final servicio = await servicioConAlarma(DateTime(2026, 6, 11, 8, 0)); final config = await servicio.posponerEjecucion( 'p1', DateTime(2026, 6, 11, 8, 30), 7, ); expect(config.alarmas.single.snoozeHasta, DateTime(2026, 6, 11, 8, 37)); }); }); group('Puente Android (MethodChannel)', () { const channel = MethodChannel('pluriwave/alarm_scheduler'); late List llamadas; late List> snoozesNativos; setUp(() { llamadas = []; snoozesNativos = []; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (call) async { llamadas.add(call); switch (call.method) { case 'scheduleAlarm': return true; case 'getNativeSnoozeState': return snoozesNativos; } return null; }); }); tearDown(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, null); }); test('programar incluye snoozeUntilMillis y snoozeOriginMillis', () async { final servicio = ServicioAlarmasAndroid(channel: channel); final snoozeHasta = DateTime(2099, 1, 1, 7, 35); final snoozeOrigen = DateTime(2099, 1, 1, 7, 30); final alarma = AlarmaMusical( id: 'pay1', nombre: 'Con snooze', hora: 7, minuto: 30, tipoProgramacion: TipoProgramacionAlarma.diaria, diasSemana: const [], proximaEjecucion: DateTime(2099, 1, 2, 7, 30), snoozeHasta: snoozeHasta, snoozeOrigen: snoozeOrigen, ); await servicio.programar(alarma); final llamada = llamadas.singleWhere((c) => c.method == 'scheduleAlarm'); final args = llamada.arguments as Map; expect(args['snoozeUntilMillis'], snoozeHasta.millisecondsSinceEpoch); expect(args['snoozeOriginMillis'], snoozeOrigen.millisecondsSinceEpoch); }); test( 'obtenerEstadoSnoozeNativo invoca getNativeSnoozeState y parsea', () async { final servicio = ServicioAlarmasAndroid(channel: channel); final hasta = DateTime(2026, 6, 11, 7, 40); final origen = DateTime(2026, 6, 11, 7, 30); snoozesNativos.add({ 'alarmId': 'nat1', 'snoozeUntilMillis': hasta.millisecondsSinceEpoch, 'snoozeOriginMillis': origen.millisecondsSinceEpoch, }); final estados = await servicio.obtenerEstadoSnoozeNativo(); expect(llamadas.map((c) => c.method), contains('getNativeSnoozeState')); expect(estados, hasLength(1)); expect(estados.single.alarmaId, 'nat1'); expect(estados.single.snoozeHasta, hasta); expect(estados.single.snoozeOrigen, origen); }, ); test('obtenerEstadoSnoozeNativo tolera lista vacia o nula', () async { final servicio = ServicioAlarmasAndroid(channel: channel); expect(await servicio.obtenerEstadoSnoozeNativo(), isEmpty); }); }); }