import 'package:flutter/material.dart';
import 'package:tm_app/core/utils/app_toast.dart';
import 'package:tm_app/core/utils/result.dart';
import 'package:tm_app/data/repositories/notification_repository.dart';
import 'package:tm_app/data/services/model/notification__response/notification_response_model.dart';
import 'package:tm_app/views/notification/strings/notification_strings.dart';

class NotificationViewModel with ChangeNotifier {
  final NotificationsRepository _repository;

  NotificationViewModel({required NotificationsRepository repositoryViewModel})
    : _repository = repositoryViewModel {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      getNotifications();
      getUnreadNotifications();
    });
  }

  bool _isLoading = false;
  String? _errorMessage;
  NotificationResponseModel? _notificationResponseModel;

  int currentPage = 1;
  static const int _pageSize = 10;
  int _totalPages = 0;
  bool _hasMoreData = true;

  bool get isLoading => _isLoading;
  String? get errorMessage => _errorMessage;
  NotificationResponseModel? get notificationResponse =>
      _notificationResponseModel;
  bool get hasMoreData => _hasMoreData;
  int get totalPages => _totalPages;

  NotificationResponseModel? _unreadNotificationResponse;
  bool _isUnreadLoading = false;

  NotificationResponseModel? get unreadNotificationResponse =>
      _unreadNotificationResponse;
  bool get isUnreadLoading => _isUnreadLoading;

  bool _isMoreLoading = false;
  bool get isMoreLoading => _isMoreLoading;

  /// Fetch notifications
  Future<void> getNotifications({int page = 1, bool isMobile = false}) async {
    if (isMobile && page > 1) {
      _isMoreLoading = true;
    } else {
      _isLoading = true;
    }
    notifyListeners();

    final int offset = _pageSize * page;

    final result = await _repository.getNotifications(
      limit: _pageSize,
      offset: offset,
    );

    switch (result) {
      case Ok<NotificationResponseModel>():
        if (isMobile && page > 1) {
          final oldNotifications =
              _notificationResponseModel?.data?.notifications ?? [];

          final newNotifications = result.value.data?.notifications ?? [];

          _notificationResponseModel = result.value.copyWith(
            data: result.value.data?.copyWith(
              notifications: [...oldNotifications, ...newNotifications],
            ),
          );
        } else {
          _notificationResponseModel = result.value;
        }

        currentPage = page;
        _hasMoreData =
            (result.value.data?.notifications?.length ?? 0) >= _pageSize;
        _totalPages = result.value.data?.meta?.pages ?? 1;
        break;

      case Error<NotificationResponseModel>():
        _errorMessage = result.error.toString();
        break;
    }

    _isLoading = false;
    _isMoreLoading = false;
    notifyListeners();
  }

  /// Jump to page
  Future<void> jumpToPage(int page) async {
    if (_totalPages == 0 || page < 1 || page > _totalPages) {
      return;
    }
    await getNotifications(page: page);
  }

  /// Mark all as read
  Future<void> markAllAsRead(BuildContext context) async {
    _isLoading = true;
    _errorMessage = null;
    notifyListeners();

    final result = await _repository.markAllAsRead();

    if (!context.mounted) {
      return;
    }

    switch (result) {
      case Ok<Map<String, dynamic>>():
        final response = result.value;
        final success = response['success'] as bool? ?? false;
        final message =
            response['message'] as String? ??
            NotificationStrings.unknownResponse;

        if (success) {
          if (_notificationResponseModel?.data?.notifications != null) {
            final updatedNotifications =
                _notificationResponseModel!.data!.notifications!
                    .map((n) => n.copyWith(seen: true))
                    .toList();

            _notificationResponseModel = _notificationResponseModel!.copyWith(
              data: _notificationResponseModel!.data!.copyWith(
                notifications: updatedNotifications,
              ),
            );

            _unreadNotificationResponse = _unreadNotificationResponse?.copyWith(
              data: _unreadNotificationResponse?.data?.copyWith(
                notifications: [],
              ),
            );
          }

          if (context.mounted) {
            AppToast.success(
              context,
              NotificationStrings.allNotificationMarkedAsRead,
            );
          }
        } else {
          _errorMessage = message;
          if (context.mounted) {
            AppToast.error(context, message);
          }
        }
        break;

      case Error<Map<String, dynamic>>():
        _errorMessage = result.error.toString();
        if (context.mounted) {
          AppToast.error(context, _errorMessage!);
        }
        break;
    }

    _isLoading = false;
    notifyListeners();
  }

  String timeAgo(String dateTimeString) {
    final createdAt = DateTime.parse(dateTimeString);
    final now = DateTime.now();
    final difference = now.difference(createdAt);

    if (difference.inMinutes < 1) {
      return NotificationStrings.now;
    } else if (difference.inMinutes < 60) {
      return '${difference.inMinutes} ${NotificationStrings.min} ';
    } else if (difference.inHours < 24) {
      return '${difference.inHours} ${NotificationStrings.hour} ';
    } else if (difference.inDays == 1) {
      return NotificationStrings.yesterday;
    } else {
      return '${difference.inDays} ${NotificationStrings.daysAgo}';
    }
  }

  Future<void> getUnreadNotifications({int page = 1}) async {
    _isUnreadLoading = true;
    notifyListeners();

    final int offset = _pageSize * page;

    final result = await _repository.getUnreadNotifications(
      limit: _pageSize,
      offset: offset,
    );

    switch (result) {
      case Ok<NotificationResponseModel>():
        _unreadNotificationResponse = result.value;
        break;
      case Error<NotificationResponseModel>():
        _errorMessage = result.error.toString();
        break;
    }

    _isUnreadLoading = false;
    notifyListeners();
  }
}
