import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'dart:io' show Platform;

import 'instance.dart';
import 'portal_shell.dart';
import 'session.dart';
import 'sign_in_screen.dart';

/// A background handler must be a top-level function or the platform will not
/// find it after the isolate is torn down.
@pragma('vm:entry-point')
Future<void> _onBackgroundMessage(RemoteMessage message) async {
  // Deliberately empty. The notification itself is displayed by the system
  // from the `notification` block; doing work here would run on a cold isolate
  // with no session and nothing useful to do with the result.
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // A build with no BASE_URL would silently point at nothing. Fail where
  // somebody will see it rather than shipping a blank app.
  assert(Instance.isConfigured, 'BASE_URL was not passed at build time');

  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_onBackgroundMessage);

  final session = Session();

  runApp(ShellApp(session: session));
}

class ShellApp extends StatelessWidget {
  const ShellApp({super.key, required this.session});

  final Session session;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Instance.appName,
      debugShowCheckedModeBanner: false,
      // Arabic-first, like everything else in this product.
      locale: const Locale('ar'),
      supportedLocales: const [Locale('ar'), Locale('en')],
      builder: (context, child) => Directionality(
        textDirection: TextDirection.rtl,
        child: child ?? const SizedBox.shrink(),
      ),
      routes: {
        '/sign-in': (_) => SignInScreen(session: session),
      },
      home: FutureBuilder<bool>(
        future: session.hasToken,
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return const Scaffold(body: Center(child: CircularProgressIndicator()));
          }

          if (!snapshot.data!) {
            return SignInScreen(session: session);
          }

          _registerForPush(session);

          return PortalShell(session: session);
        },
      ),
    );
  }

  /// Push is registered natively, not through the page — that is one of the
  /// few things a wrapper genuinely adds, and it is also part of why the
  /// submission is not a "minimum functionality" rejection.
  Future<void> _registerForPush(Session session) async {
    final messaging = FirebaseMessaging.instance;

    final settings = await messaging.requestPermission();

    if (settings.authorizationStatus == AuthorizationStatus.denied) return;

    final token = await messaging.getToken();

    if (token == null) return;

    final info = await PackageInfo.fromPlatform();

    await session.registerPushToken(
      token,
      Platform.isIOS ? 'ios' : 'android',
      info.appName,
    );

    // A rotated token that is never re-registered is a member who silently
    // stops receiving anything.
    messaging.onTokenRefresh.listen((refreshed) {
      session.registerPushToken(refreshed, Platform.isIOS ? 'ios' : 'android', info.appName);
    });
  }
}
