import 'package:flutter/material.dart';

import 'package:pweb/utils/error/handler.dart';
import 'package:pweb/utils/snackbar.dart';
import 'package:pweb/widgets/error/content.dart';

import 'package:pweb/generated/i18n/app_localizations.dart';


Future<void> notifyUserOfErrorX({
  required BuildContext context,
  required String errorSituation,
  required Object exception,
  required AppLocalizations appLocalizations,
  int delaySeconds = 3,
}) async {
  if (!context.mounted) return;
  if (!_shouldShowError(errorSituation, exception)) {
    return;
  }
  final localizedError = ErrorHandler.handleErrorLocs(appLocalizations, exception);
  final technicalDetails = exception.toString();
  final scaffoldMessenger = ScaffoldMessenger.maybeOf(context);

  if (scaffoldMessenger != null) {
    final durationSeconds = _normalizeDelaySeconds(delaySeconds);
    scaffoldMessenger.clearSnackBars();
    final snackBar = _buildMainErrorSnackBar(
      errorSituation: errorSituation,
      localizedError: localizedError,
      technicalDetails: technicalDetails,
      loc: appLocalizations,
      scaffoldMessenger: scaffoldMessenger,
      delaySeconds: durationSeconds,
    );
    scaffoldMessenger.showSnackBar(snackBar);
    return;
  }

  await _showErrorDialog(
    context,
    title: errorSituation,
    message: localizedError,
  );
}

void showErrorSnackBar({
  required ScaffoldMessengerState scaffoldMessenger,
  required String errorSituation,
  required Object exception,
  required AppLocalizations appLocalizations,
  int delaySeconds = 3,
}) {
  if (!_shouldShowError(errorSituation, exception)) {
    return;
  }
  final localizedError = ErrorHandler.handleErrorLocs(appLocalizations, exception);
  final technicalDetails = exception.toString();
  final durationSeconds = _normalizeDelaySeconds(delaySeconds);
  scaffoldMessenger.clearSnackBars();
  final snackBar = _buildMainErrorSnackBar(
    errorSituation: errorSituation,
    localizedError: localizedError,
    technicalDetails: technicalDetails,
    loc: appLocalizations,
    scaffoldMessenger: scaffoldMessenger,
    delaySeconds: durationSeconds,
  );
  scaffoldMessenger.showSnackBar(snackBar);
}

Future<void> notifyUserOfError({
  required BuildContext context,
  required String errorSituation,
  required Object exception,
  int delaySeconds = 3,
}) =>
    notifyUserOfErrorX(
      context: context,
      errorSituation: errorSituation,
      exception: exception,
      appLocalizations: AppLocalizations.of(context)!,
      delaySeconds: delaySeconds,
    );

Future<T?> executeActionWithNotification<T>({
  required BuildContext context,
  required Future<T> Function() action,
  required String errorMessage,
  String? successMessage,
  int delaySeconds = 3,
}) async {
  final localizations = AppLocalizations.of(context)!;

  try {
    final result = await action();
    if (successMessage != null) {
      await notifyUser(context, successMessage, delaySeconds: delaySeconds);
    }
    return result;
  } catch (e) {
    await notifyUserOfErrorX(
      context: context,
      errorSituation: errorMessage,
      exception: e,
      appLocalizations: localizations,
      delaySeconds: delaySeconds,
    );
  }
  return null;
}

Future<void> postNotifyUserOfError({
  required BuildContext context,
  required String errorSituation,
  required Object exception,
  required AppLocalizations appLocalizations,
  int delaySeconds = 3,
}) =>
    notifyUserOfErrorX(
      context: context,
      errorSituation: errorSituation,
      exception: exception,
      appLocalizations: appLocalizations,
      delaySeconds: delaySeconds,
    );

Future<void> postNotifyUserOfErrorX({
  required BuildContext context,
  required String errorSituation,
  required Object exception,
  int delaySeconds = 3,
}) =>
    postNotifyUserOfError(
      context: context,
      errorSituation: errorSituation,
      exception: exception,
      appLocalizations: AppLocalizations.of(context)!,
      delaySeconds: delaySeconds,
    );


SnackBar _buildMainErrorSnackBar({
  required String errorSituation,
  required String localizedError,
  required String technicalDetails,
  required AppLocalizations loc,
  required ScaffoldMessengerState scaffoldMessenger,
  int delaySeconds = 3,
}) =>
    SnackBar(
      duration: Duration(seconds: _normalizeDelaySeconds(delaySeconds)),
      content: ErrorSnackBarContent(
        situation: errorSituation,
        localizedError: localizedError,
      ),
      action: SnackBarAction(
        label: loc.showDetailsAction,
        onPressed: () {
          scaffoldMessenger.hideCurrentSnackBar();
          scaffoldMessenger.showSnackBar(
            SnackBar(
              content: Text(technicalDetails),
              duration: const Duration(seconds: 6),
            ),
          );
        },
      ),
    );

Future<void> _showErrorDialog(
  BuildContext context, {
  required String title,
  required String message,
}) async {
  if (!context.mounted) return;
  final loc = AppLocalizations.of(context)!;
  await showDialog<void>(
    context: context,
    builder: (dialogContext) => AlertDialog(
      title: Text(title),
      content: Text(message),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(dialogContext).pop(),
          child: Text(loc.ok),
        ),
      ],
    ),
  );
}

int _normalizeDelaySeconds(int delaySeconds) =>
    delaySeconds <= 0 ? 3 : delaySeconds;

String? _lastErrorSignature;
DateTime? _lastErrorShownAt;
const int _errorCooldownSeconds = 60;

bool _shouldShowError(String errorSituation, Object exception) {
  final signature = '$errorSituation|${exception.runtimeType}|${exception.toString()}';
  final now = DateTime.now();

  if (_lastErrorSignature == signature) {
    final lastShownAt = _lastErrorShownAt;
    if (lastShownAt != null &&
        now.difference(lastShownAt).inSeconds < _errorCooldownSeconds) {
      return false;
    }
  }

  _lastErrorSignature = signature;
  _lastErrorShownAt = now;
  return true;
}
