import 'package:comunic/helpers/firebase_messaging_helper.dart';
import 'package:comunic/helpers/independent_push_notifications_helper.dart';
import 'package:comunic/helpers/push_notifications_helper.dart';
import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/config.dart';
import 'package:comunic/ui/widgets/async_screen_widget.dart';
import 'package:comunic/utils/flutter_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/log_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';

/// Push notifications configuration route
///
/// @author Pierre Hubert

Future<void> showInitialPushNotificationsConfiguration(
    BuildContext context) async {
  // Check if no notifications service are available
  if (!PushNotificationsHelper.arePushNotificationsAvailable) return;

  await Navigator.of(context).push(
      MaterialPageRoute(builder: (c) => PushNotificationsConfigurationRoute()));
}

class PushNotificationsConfigurationRoute extends StatefulWidget {
  @override
  _PushNotificationsConfigurationRouteState createState() =>
      _PushNotificationsConfigurationRouteState();
}

class _PushNotificationsConfigurationRouteState
    extends State<PushNotificationsConfigurationRoute> {
  final _key = GlobalKey<PushNotificationsConfigurationWidgetState>();

  @override
  Widget build(BuildContext context) => Material(
        textStyle: TextStyle(color: Colors.white),
        color: config().splashBackgroundColor,
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Spacer(),
                Icon(Icons.notifications_none, color: Colors.white),
                Spacer(),
                PushNotificationsConfigurationWidget(
                  key: _key,
                  onConfigured: () => (Navigator.of(context).pop()),
                  onChanged: () => setState(() {}),
                ),
                Spacer(),
                OutlinedButton(
                    onPressed: _key?.currentState?.canSubmit ?? false
                        ? _key.currentState.submit
                        : null,
                    child: Text(tr("Configure").toUpperCase()),
                    style: OutlinedButton.styleFrom(primary: Colors.white)),
                Spacer(),
              ],
            ),
          ),
        ),
      );
}

class PushNotificationsConfigurationWidget extends StatefulWidget {
  final Function() onConfigured;
  final Function() onChanged;

  const PushNotificationsConfigurationWidget({
    Key key,
    @required this.onConfigured,
    @required this.onChanged,
  }) : super(key: key);

  @override
  PushNotificationsConfigurationWidgetState createState() =>
      PushNotificationsConfigurationWidgetState();
}

class PushNotificationsConfigurationWidgetState
    extends State<PushNotificationsConfigurationWidget> {
  PushNotificationsStatus currStatus;

  bool get canSubmit =>
      (currStatus ?? PushNotificationsStatus.UNDEFINED) !=
      PushNotificationsStatus.UNDEFINED;

  Future<void> _refresh() async {
    await PushNotificationsHelper.refreshLocalStatus();
    currStatus = await PushNotificationsHelper.getLocalStatus();

    if (currStatus == PushNotificationsStatus.UNDEFINED &&
        srvConfig.notificationsPolicy.hasFirebase)
      currStatus = PushNotificationsStatus.FIREBASE;

    widget.onChanged();
  }

  @override
  Widget build(BuildContext context) {
    return AsyncScreenWidget(
      onReload: _refresh,
      onBuild: _buildForm,
      errorMessage: tr("Failed to load push notifications settings!"),
    );
  }

  Widget _buildForm() => ConstrainedBox(
        constraints: BoxConstraints(maxWidth: 300),
        child: Column(
          children: [
            Text(
              tr("%app% can send you push notifications to your device.",
                  args: {
                    "app": config().appName,
                  }),
              textAlign: TextAlign.center,
            ),
            SizedBox(height: 10),
            _NotificationOption(
              title: tr("Use Google services (recommended)"),
              description: tr("Save your battery life."),
              option: PushNotificationsStatus.FIREBASE,
              current: currStatus,
              available: srvConfig.notificationsPolicy.hasFirebase,
              onChanged: (s) {
                setState(() => currStatus = s);
                if (widget.onChanged != null) widget.onChanged();
              },
            ),
            SizedBox(height: 5),
            _NotificationOption(
              title: tr("Use independent notifications service"),
              description: tr(
                  "Protect more your privacy, but drains battery and is less reliable."),
              option: PushNotificationsStatus.INDEPENDENT,
              current: currStatus,
              available:
                  srvConfig.notificationsPolicy.hasIndependent && isAndroid,
              onChanged: (s) {
                setState(() => currStatus = s);
                if (widget.onChanged != null) widget.onChanged();
              },
            ),
            SizedBox(height: 5),
            _NotificationOption(
              title: tr("Do not send notification"),
              option: PushNotificationsStatus.DISABLED,
              current: currStatus,
              available: true,
              onChanged: (s) {
                setState(() => currStatus = s);
                if (widget.onChanged != null) widget.onChanged();
              },
            ),
          ],
        ),
      );

  Future<bool> submit() async {
    try {
      String firebaseToken = "";

      if (currStatus == await PushNotificationsHelper.getLocalStatus()) {
        widget.onConfigured();
        return true;
      }

      switch (currStatus) {
        case PushNotificationsStatus.DISABLED:
          break;

        case PushNotificationsStatus.FIREBASE:
          await FirebaseMessagingHelper.preConfigure();
          firebaseToken = await FirebaseMessagingHelper.getToken();
          break;

        case PushNotificationsStatus.INDEPENDENT:
          if (await IndependentPushNotificationsHelper.needPreConfiguration())
            await IndependentPushNotificationsHelper.preConfigure(context);
          break;

        default:
          throw new Exception("Unknown status!");
      }

      await PushNotificationsHelper.clearLocalStatus();
      await PushNotificationsHelper.setNewStatus(currStatus,
          firebaseToken: firebaseToken);
      await PushNotificationsHelper.refreshLocalStatus();

      widget.onConfigured();
    } catch (e, s) {
      logError(e, s);
      showAlert(
          context: context,
          message: tr("Failed to configure push notifications!"));
      return false;
    }
    return true;
  }
}

class _NotificationOption extends StatelessWidget {
  final String title;
  final String description;
  final PushNotificationsStatus option;
  final PushNotificationsStatus current;
  final bool available;
  final Function(PushNotificationsStatus) onChanged;

  const _NotificationOption({
    Key key,
    @required this.title,
    this.description,
    @required this.option,
    @required this.current,
    @required this.available,
    @required this.onChanged,
  })  : assert(title != null),
        assert(option != null),
        assert(current != null),
        assert(available != null),
        assert(onChanged != null),
        super(key: key);

  @override
  Widget build(BuildContext context) => !available
      ? Container()
      : Theme(
          data: Theme.of(context).copyWith(
              splashColor: Colors.transparent,
              highlightColor: Colors.transparent),
          child: ListTile(
            leading: Radio(
              value: option,
              groupValue: current,
              onChanged: onChanged,
              fillColor: MaterialStateProperty.all(Colors.white),
            ),
            title: Text(title, style: TextStyle(color: Colors.white)),
            subtitle: description == null
                ? null
                : Text(description, style: TextStyle(color: Colors.white)),
            contentPadding: EdgeInsets.all(0),
            onTap: () => onChanged(option),
          ),
        );
}