import 'dart:convert';

import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;

import '../local/models/app_settings.dart';
import 'notification_inbox_service.dart';
import 'notification_runtime_service.dart';
import 'notification_service.dart';

/// Pulls server-defined notification content and maps it to local inbox items.
class RemoteNotificationContentService {
  RemoteNotificationContentService._();
  static final RemoteNotificationContentService instance =
      RemoteNotificationContentService._();

  final NotificationInboxService _inbox = NotificationInboxService.instance;
  final NotificationRuntimeService _runtime =
      NotificationRuntimeService.instance;

  Future<void> sync({
    required AppSettings settings,
  }) async {
    if (!settings.inboxEnabled) return;

    final endpoint = (dotenv.env['NOTIFICATION_FEED_URL'] ?? '').trim();
    if (endpoint.isEmpty) return;

    final now = DateTime.now();
    final lastSync = _runtime.lastRemoteSyncAt();
    if (lastSync != null &&
        now.difference(lastSync) < const Duration(hours: 6)) {
      return;
    }

    try {
      final response = await http.get(Uri.parse(endpoint));
      if (response.statusCode < 200 || response.statusCode >= 300) return;

      final decoded = json.decode(response.body);
      final items = _extractItems(decoded);
      if (items.isEmpty) return;

      for (final raw in items) {
        final id = (raw['id'] ?? '').toString().trim();
        final title = (raw['title'] ?? '').toString().trim();
        final body = (raw['body'] ?? '').toString().trim();
        if (id.isEmpty || title.isEmpty || body.isEmpty) continue;

        final deeplink = (raw['deeplink'] ?? '').toString().trim();
        final type = (raw['type'] ?? 'content').toString().trim();
        final expiresAt =
            DateTime.tryParse((raw['expiresAt'] ?? '').toString().trim());
        final isPinned = raw['isPinned'] == true;
        final shouldPush = raw['push'] == true;

        await _inbox.addItem(
          title: title,
          body: body,
          type: type.isEmpty ? 'content' : type,
          source: 'remote',
          deeplink: deeplink.isEmpty ? null : deeplink,
          dedupeKey: 'remote.$id',
          expiresAt: expiresAt,
          isPinned: isPinned,
          meta: <String, dynamic>{'remoteId': id},
        );

        if (shouldPush && settings.alertsEnabled) {
          final notif = NotificationService.instance;
          await notif.showNonPrayerAlert(
            settings: settings,
            id: notif.nonPrayerNotificationId('remote.push.$id'),
            title: title,
            body: body,
            payloadType: 'content',
            silent: true,
          );
        }
      }

      await _runtime.setLastRemoteSyncAt(now);
    } catch (_) {
      // Non-fatal: remote feed is optional.
    }
  }

  List<Map<String, dynamic>> _extractItems(dynamic decoded) {
    if (decoded is List) {
      return decoded.whereType<Map>().map(_toStringKeyedMap).toList();
    }
    if (decoded is Map) {
      final list = decoded['items'];
      if (list is List) {
        return list.whereType<Map>().map(_toStringKeyedMap).toList();
      }
    }
    return const <Map<String, dynamic>>[];
  }

  Map<String, dynamic> _toStringKeyedMap(Map raw) {
    return raw.map((key, value) => MapEntry(key.toString(), value));
  }
}
