import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';

import '../globals.dart';
import '../models/exec_error.dart';
import '../models/user_notification.dart';
import '../routes.dart';
import '../services/connections_manager.dart';
import '../services/notifications_manager.dart';
import '../services/timeline_manager.dart';
import '../utils/active_profile_selector.dart';
import '../utils/dateutils.dart';
import '../utils/snackbar_builder.dart';
import 'html_text_viewer_control.dart';
import 'image_control.dart';

class NotificationControl extends StatelessWidget {
  static final _logger = Logger('$NotificationControl');
  final UserNotification notification;
  bool _processingTap = false;

  NotificationControl({
    super.key,
    required this.notification,
  });

  Future<void> _goToStatus(BuildContext context) async {
    final manager =
        getIt<ActiveProfileSelector<TimelineManager>>().activeEntry.value;
    final existingPostData = manager.getPostTreeEntryBy(notification.iid);
    if (existingPostData.isSuccess) {
      context
          .push('/post/view/${existingPostData.value.id}/${notification.iid}');
      return;
    }
    final loadedPost = await manager.refreshStatusChain(notification.iid);
    if (loadedPost.isSuccess) {
      context.push('/post/view/${loadedPost.value.id}/${notification.iid}');
      return;
    }
    buildSnackbar(
        context, 'Error getting data for notification: ${loadedPost.error}');
  }

  @override
  Widget build(BuildContext context) {
    const iconSize = 50.0;
    final manager = context
        .watch<ActiveProfileSelector<NotificationsManager>>()
        .activeEntry
        .fold(
          onSuccess: (manager) => manager,
          onError: (error) {
            _logger.severe('Error getting notification manager: $error');
            return null;
          },
        );

    final fromIcon = getIt<ActiveProfileSelector<ConnectionsManager>>()
        .activeEntry
        .andThen((manager) => manager.getById(notification.fromId))
        .fold(
          onSuccess: (connection) => ImageControl(
            imageUrl: connection.avatarUrl.toString(),
            iconOverride: const Icon(Icons.person),
            width: iconSize,
            height: iconSize,
            onTap: () async {
              context.pushNamed(ScreenPaths.userProfile,
                  pathParameters: {'id': notification.fromId});
            },
          ),
          onError: (error) => GestureDetector(
            onTap: () async {
              context.pushNamed(ScreenPaths.userProfile,
                  pathParameters: {'id': notification.fromId});
            },
            child: const SizedBox(
              width: iconSize,
              height: iconSize,
              child: Icon(Icons.person),
            ),
          ),
        );

    Function()? onTapCallFunction;
    switch (notification.type) {
      case NotificationType.follow:
        onTapCallFunction = () async {
          await context.pushNamed(ScreenPaths.userProfile,
              pathParameters: {'id': notification.fromId});
        };
        break;
      case NotificationType.follow_request:
        onTapCallFunction = () async {
          await context.push('/connect/${notification.fromId}');
        };
        break;
      case NotificationType.unknown:
        buildSnackbar(context, 'Unknown message type, nothing to do');
        break;
      case NotificationType.favourite:
      case NotificationType.mention:
      case NotificationType.reshare:
      case NotificationType.reblog:
      case NotificationType.status:
        onTapCallFunction = () async {
          await _goToStatus(context);
        };
        break;
      case NotificationType.direct_message:
        onTapCallFunction = () async => await context.pushNamed(
              ScreenPaths.thread,
              queryParameters: {'uri': notification.iid},
            );
        break;
    }

    final onTap = onTapCallFunction == null
        ? null
        : () async {
            if (_processingTap) {
              return true;
            }

            _tapProcessingStarted();
            await onTapCallFunction!();
            _tapProcessingStop();
            return true;
          };

    return ListTile(
      tileColor: notification.dismissed ? null : Colors.black12,
      leading: fromIcon,
      title: GestureDetector(
        onTap: onTap,
        child: HtmlTextViewerControl(
          content: notification.content,
          onTapUrl: (_) async => onTap!(),
        ),
      ),
      subtitle: GestureDetector(
        onTap: onTap,
        child: Text(
          ElapsedDateUtils.epochSecondsToString(notification.timestamp),
        ),
      ),
      trailing: notification.dismissed ||
              notification.type == NotificationType.direct_message
          ? null
          : IconButton(
              onPressed: manager == null
                  ? null
                  : () async {
                      await manager.markSeen(notification).withError((error) {
                        buildSnackbar(
                            context, 'Error marking notification: $error');
                        logError(error, _logger);
                      });
                    },
              icon: const Icon(Icons.close_rounded)),
    );
  }

  void _tapProcessingStarted() {
    _processingTap = true;
    Future.delayed(Duration(seconds: 10), () => _processingTap = false);
  }

  void _tapProcessingStop() {
    _processingTap = false;
  }
}
