import 'dart:async';

import 'package:flutter/services.dart';

import '../modelos/alarma_musical.dart';

class EventoAlarmaAndroid {
  const EventoAlarmaAndroid({
    required this.alarmaId,
    required this.titulo,
    required this.accion,
  });

  final String alarmaId;
  final String titulo;
  final String accion;

  factory EventoAlarmaAndroid.fromMap(Map<Object?, Object?> map) {
    return EventoAlarmaAndroid(
      alarmaId: map['alarmId'] as String? ?? '',
      titulo: map['alarmTitle'] as String? ?? 'PluriWave',
      accion: map['alarmAction'] as String? ?? '',
    );
  }
}

class DiagnosticoAlarmasAndroid {
  const DiagnosticoAlarmasAndroid({
    required this.puedeProgramarExactas,
    required this.notificacionesPermitidas,
    required this.fabricante,
    required this.versionSdk,
  });

  final bool puedeProgramarExactas;
  final bool notificacionesPermitidas;
  final String fabricante;
  final int versionSdk;

  factory DiagnosticoAlarmasAndroid.fromMap(Map<Object?, Object?> map) {
    return DiagnosticoAlarmasAndroid(
      puedeProgramarExactas: map['canScheduleExactAlarms'] as bool? ?? true,
      notificacionesPermitidas: map['notificationsEnabled'] as bool? ?? true,
      fabricante: map['manufacturer'] as String? ?? 'Android',
      versionSdk: map['sdkInt'] as int? ?? 0,
    );
  }
}

class ServicioAlarmasAndroid {
  ServicioAlarmasAndroid({
    MethodChannel channel = const MethodChannel('pluriwave/alarm_scheduler'),
  }) : _channel = channel {
    _instalarHandler(_channel);
  }

  final MethodChannel _channel;
  static final _eventosController =
      StreamController<EventoAlarmaAndroid>.broadcast();
  static bool _handlerInstalado = false;

  Stream<EventoAlarmaAndroid> get eventosAlarma => _eventosController.stream;

  Future<void> programar(AlarmaMusical alarma) async {
    final proxima = alarma.proximaEjecucion;
    if (proxima == null || !alarma.activa) {
      await cancelar(alarma.id);
      return;
    }
    await _channel.invokeMethod<void>('scheduleAlarm', {
      'id': alarma.id,
      'title': alarma.nombre,
      'triggerAtMillis': proxima.millisecondsSinceEpoch,
      'preNoticeAtMillis':
          proxima.subtract(const Duration(minutes: 30)).millisecondsSinceEpoch,
    });
  }

  Future<void> cancelar(String alarmaId) =>
      _channel.invokeMethod<void>('cancelAlarm', {'id': alarmaId});

  Future<void> ocultarNotificacionAlarma(String alarmaId) => _channel
      .invokeMethod<void>('dismissAlarmNotification', {'id': alarmaId});

  Future<DiagnosticoAlarmasAndroid> diagnostico() async {
    final raw = await _channel.invokeMethod<Map<Object?, Object?>>(
      'diagnostics',
    );
    return DiagnosticoAlarmasAndroid.fromMap(raw ?? const {});
  }

  Future<EventoAlarmaAndroid?> obtenerEventoInicial() async {
    final raw = await _channel.invokeMethod<Map<Object?, Object?>>(
      'getInitialAlarmIntent',
    );
    if (raw == null || raw.isEmpty) return null;
    final evento = EventoAlarmaAndroid.fromMap(raw);
    return evento.alarmaId.isEmpty ? null : evento;
  }

  static void _instalarHandler(MethodChannel channel) {
    if (_handlerInstalado) return;
    _handlerInstalado = true;
    channel.setMethodCallHandler((call) async {
      if (call.method != 'alarmFired') return;
      final args = call.arguments;
      if (args is Map) {
        final evento = EventoAlarmaAndroid.fromMap(args);
        if (evento.alarmaId.isNotEmpty) {
          _eventosController.add(evento);
        }
      }
    });
  }
}
