// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/widgets.dart';

import 'configuration.dart';
import 'logging.dart';
import 'match.dart';
import 'misc/error_screen.dart';
import 'misc/errors.dart';
import 'pages/cupertino.dart';
import 'pages/custom_transition_page.dart';
import 'pages/material.dart';
import 'route.dart';
import 'route_data.dart';
import 'state.dart';

/// Signature of a go router builder function with navigator.
typedef GoRouterBuilderWithNav = Widget Function(
  BuildContext context,
  Widget child,
);

typedef _PageBuilderForAppType = Page<void> Function({
  required LocalKey key,
  required String? name,
  required Object? arguments,
  required String restorationId,
  required Widget child,
});

typedef _ErrorBuilderForAppType = Widget Function(
  BuildContext context,
  GoRouterState state,
);

/// Signature for a function that takes in a `route` to be popped with
/// the `result` and returns a boolean decision on whether the pop
/// is successful.
///
/// The `match` is the corresponding [RouteMatch] the `route`
/// associates with.
///
/// Used by of [RouteBuilder.onPopPageWithRouteMatch].
typedef PopPageWithRouteMatchCallback = bool Function(
    Route<dynamic> route, dynamic result, RouteMatchBase match);

/// Builds the top-level Navigator for GoRouter.
class RouteBuilder {
  /// [RouteBuilder] constructor.
  RouteBuilder({
    required this.configuration,
    required this.builderWithNav,
    required this.errorPageBuilder,
    required this.errorBuilder,
    required this.restorationScopeId,
    required this.observers,
    required this.onPopPageWithRouteMatch,
    this.requestFocus = true,
  });

  /// Builder function for a go router with Navigator.
  final GoRouterBuilderWithNav builderWithNav;

  /// Error page builder for the go router delegate.
  final GoRouterPageBuilder? errorPageBuilder;

  /// Error widget builder for the go router delegate.
  final GoRouterWidgetBuilder? errorBuilder;

  /// The route configuration for the app.
  final RouteConfiguration configuration;

  /// Restoration ID to save and restore the state of the navigator, including
  /// its history.
  final String? restorationScopeId;

  /// Whether or not the navigator created by this builder and it's new topmost route should request focus
  /// when the new route is pushed onto the navigator.
  ///
  /// Defaults to true.
  final bool requestFocus;

  /// NavigatorObserver used to receive notifications when navigating in between routes.
  /// changes.
  final List<NavigatorObserver> observers;

  /// A callback called when a `route` produced by `match` is about to be popped
  /// with the `result`.
  ///
  /// If this method returns true, this builder pops the `route` and `match`.
  ///
  /// If this method returns false, this builder aborts the pop.
  final PopPageWithRouteMatchCallback onPopPageWithRouteMatch;

  /// Builds the top-level Navigator for the given [RouteMatchList].
  Widget build(
    BuildContext context,
    RouteMatchList matchList,
    bool routerNeglect,
  ) {
    if (matchList.isEmpty && !matchList.isError) {
      // The build method can be called before async redirect finishes. Build a
      // empty box until then.
      return const SizedBox.shrink();
    }
    assert(matchList.isError || !matchList.last.route.redirectOnly);
    return builderWithNav(
      context,
      _CustomNavigator(
        navigatorKey: configuration.navigatorKey,
        observers: observers,
        navigatorRestorationId: restorationScopeId,
        onPopPageWithRouteMatch: onPopPageWithRouteMatch,
        matchList: matchList,
        matches: matchList.matches,
        configuration: configuration,
        errorBuilder: errorBuilder,
        errorPageBuilder: errorPageBuilder,
      ),
    );
  }
}

class _CustomNavigator extends StatefulWidget {
  const _CustomNavigator({
    super.key,
    required this.navigatorKey,
    required this.observers,
    required this.navigatorRestorationId,
    required this.onPopPageWithRouteMatch,
    required this.matchList,
    required this.matches,
    required this.configuration,
    required this.errorBuilder,
    required this.errorPageBuilder,
  });

  final GlobalKey<NavigatorState> navigatorKey;
  final List<NavigatorObserver> observers;

  /// The actual [RouteMatchBase]s to be built.
  ///
  /// This can be different from matches in [matchList] if this widget is used
  /// to build navigator in shell route. In this case, these matches come from
  /// the [ShellRouteMatch.matches].
  final List<RouteMatchBase> matches;
  final RouteMatchList matchList;
  final RouteConfiguration configuration;
  final PopPageWithRouteMatchCallback onPopPageWithRouteMatch;
  final String? navigatorRestorationId;
  final GoRouterWidgetBuilder? errorBuilder;
  final GoRouterPageBuilder? errorPageBuilder;

  @override
  State<StatefulWidget> createState() => _CustomNavigatorState();
}

class _CustomNavigatorState extends State<_CustomNavigator> {
  HeroController? _controller;
  late Map<Page<Object?>, RouteMatchBase> _pageToRouteMatchBase;
  final GoRouterStateRegistry _registry = GoRouterStateRegistry();
  List<Page<Object?>>? _pages;

  @override
  void didUpdateWidget(_CustomNavigator oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.matchList != oldWidget.matchList) {
      _pages = null;
    }
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // Create a HeroController based on the app type.
    if (_controller == null) {
      if (isMaterialApp(context)) {
        _controller = createMaterialHeroController();
      } else if (isCupertinoApp(context)) {
        _controller = createCupertinoHeroController();
      } else {
        _controller = HeroController();
      }
    }
    // This method can also be called if any of the page builders depend on
    // the context. In this case, make sure _pages are rebuilt.
    _pages = null;
  }

  @override
  void dispose() {
    _controller?.dispose();
    _registry.dispose();
    super.dispose();
  }

  void _updatePages(BuildContext context) {
    assert(_pages == null);
    final List<Page<Object?>> pages = <Page<Object?>>[];
    final Map<Page<Object?>, RouteMatchBase> pageToRouteMatchBase =
        <Page<Object?>, RouteMatchBase>{};
    final Map<Page<Object?>, GoRouterState> registry =
        <Page<Object?>, GoRouterState>{};
    if (widget.matchList.isError) {
      pages.add(_buildErrorPage(context, widget.matchList));
    } else {
      for (final RouteMatchBase match in widget.matches) {
        final Page<Object?>? page = _buildPage(context, match);
        if (page == null) {
          continue;
        }
        pages.add(page);
        pageToRouteMatchBase[page] = match;
        registry[page] =
            match.buildState(widget.configuration, widget.matchList);
      }
    }
    _pages = pages;
    _registry.updateRegistry(registry);
    _pageToRouteMatchBase = pageToRouteMatchBase;
  }

  Page<Object?>? _buildPage(BuildContext context, RouteMatchBase match) {
    if (match is RouteMatch) {
      if (match is ImperativeRouteMatch && match.matches.isError) {
        return _buildErrorPage(context, match.matches);
      }
      return _buildPageForGoRoute(context, match);
    }
    if (match is ShellRouteMatch) {
      return _buildPageForShellRoute(context, match);
    }
    throw GoError('unknown match type ${match.runtimeType}');
  }

  /// Builds a [Page] for a [RouteMatch]
  Page<Object?>? _buildPageForGoRoute(BuildContext context, RouteMatch match) {
    final GoRouterPageBuilder? pageBuilder = match.route.pageBuilder;
    final GoRouterState state =
        match.buildState(widget.configuration, widget.matchList);
    if (pageBuilder != null) {
      final Page<Object?> page = pageBuilder(context, state);
      if (page is! NoOpPage) {
        return page;
      }
    }

    final GoRouterWidgetBuilder? builder = match.route.builder;

    if (builder == null) {
      return null;
    }
    return _buildPlatformAdapterPage(context, state,
        Builder(builder: (BuildContext context) {
      return builder(context, state);
    }));
  }

  /// Builds a [Page] for a [ShellRouteMatch]
  Page<Object?> _buildPageForShellRoute(
    BuildContext context,
    ShellRouteMatch match,
  ) {
    final GoRouterState state =
        match.buildState(widget.configuration, widget.matchList);
    final GlobalKey<NavigatorState> navigatorKey = match.navigatorKey;
    final ShellRouteContext shellRouteContext = ShellRouteContext(
      route: match.route,
      routerState: state,
      navigatorKey: navigatorKey,
      routeMatchList: widget.matchList,
      navigatorBuilder:
          (List<NavigatorObserver>? observers, String? restorationScopeId) {
        return _CustomNavigator(
          // The state needs to persist across rebuild.
          key: GlobalObjectKey(navigatorKey.hashCode),
          navigatorRestorationId: restorationScopeId,
          navigatorKey: navigatorKey,
          matches: match.matches,
          matchList: widget.matchList,
          configuration: widget.configuration,
          observers: observers ?? const <NavigatorObserver>[],
          onPopPageWithRouteMatch: widget.onPopPageWithRouteMatch,
          // This is used to recursively build pages under this shell route.
          errorBuilder: widget.errorBuilder,
          errorPageBuilder: widget.errorPageBuilder,
        );
      },
    );
    final Page<Object?>? page =
        match.route.buildPage(context, state, shellRouteContext);
    if (page != null && page is! NoOpPage) {
      return page;
    }

    // Return the result of the route's builder() or pageBuilder()
    return _buildPlatformAdapterPage(
      context,
      state,
      Builder(
        builder: (BuildContext context) {
          return match.route.buildWidget(context, state, shellRouteContext)!;
        },
      ),
    );
  }

  _PageBuilderForAppType? _pageBuilderForAppType;

  _ErrorBuilderForAppType? _errorBuilderForAppType;

  void _cacheAppType(BuildContext context) {
    // cache app type-specific page and error builders
    if (_pageBuilderForAppType == null) {
      assert(_errorBuilderForAppType == null);

      // can be null during testing
      final Element? elem = context is Element ? context : null;

      if (elem != null && isMaterialApp(elem)) {
        log('Using MaterialApp configuration');
        _pageBuilderForAppType = pageBuilderForMaterialApp;
        _errorBuilderForAppType =
            (BuildContext c, GoRouterState s) => MaterialErrorScreen(s.error);
      } else if (elem != null && isCupertinoApp(elem)) {
        log('Using CupertinoApp configuration');
        _pageBuilderForAppType = pageBuilderForCupertinoApp;
        _errorBuilderForAppType =
            (BuildContext c, GoRouterState s) => CupertinoErrorScreen(s.error);
      } else {
        log('Using WidgetsApp configuration');
        _pageBuilderForAppType = ({
          required LocalKey key,
          required String? name,
          required Object? arguments,
          required String restorationId,
          required Widget child,
        }) =>
            NoTransitionPage<void>(
              name: name,
              arguments: arguments,
              key: key,
              restorationId: restorationId,
              child: child,
            );
        _errorBuilderForAppType =
            (BuildContext c, GoRouterState s) => ErrorScreen(s.error);
      }
    }

    assert(_pageBuilderForAppType != null);
    assert(_errorBuilderForAppType != null);
  }

  /// builds the page based on app type, i.e. MaterialApp vs. CupertinoApp
  Page<Object?> _buildPlatformAdapterPage(
    BuildContext context,
    GoRouterState state,
    Widget child,
  ) {
    // build the page based on app type
    _cacheAppType(context);
    return _pageBuilderForAppType!(
      key: state.pageKey,
      name: state.name ?? state.path,
      arguments: <String, String>{
        ...state.pathParameters,
        ...state.uri.queryParameters
      },
      restorationId: state.pageKey.value,
      child: child,
    );
  }

  GoRouterState _buildErrorState(RouteMatchList matchList) {
    assert(matchList.isError);
    return GoRouterState(
      widget.configuration,
      uri: matchList.uri,
      matchedLocation: matchList.uri.path,
      fullPath: matchList.fullPath,
      pathParameters: matchList.pathParameters,
      error: matchList.error,
      pageKey: ValueKey<String>('${matchList.uri}(error)'),
      topRoute: matchList.lastOrNull?.route,
    );
  }

  /// Builds a an error page.
  Page<void> _buildErrorPage(BuildContext context, RouteMatchList matchList) {
    final GoRouterState state = _buildErrorState(matchList);
    assert(state.error != null);

    // If the error page builder is provided, use that, otherwise, if the error
    // builder is provided, wrap that in an app-specific page (for example,
    // MaterialPage). Finally, if nothing is provided, use a default error page
    // wrapped in the app-specific page.
    _cacheAppType(context);
    final GoRouterWidgetBuilder? errorBuilder = widget.errorBuilder;
    return widget.errorPageBuilder != null
        ? widget.errorPageBuilder!(context, state)
        : _buildPlatformAdapterPage(
            context,
            state,
            errorBuilder != null
                ? errorBuilder(context, state)
                : _errorBuilderForAppType!(context, state),
          );
  }

  bool _handlePopPage(Route<Object?> route, Object? result) {
    final Page<Object?> page = route.settings as Page<Object?>;
    final RouteMatchBase match = _pageToRouteMatchBase[page]!;
    return widget.onPopPageWithRouteMatch(route, result, match);
  }

  @override
  Widget build(BuildContext context) {
    if (_pages == null) {
      _updatePages(context);
    }
    assert(_pages != null);
    return GoRouterStateRegistryScope(
      registry: _registry,
      child: HeroControllerScope(
        controller: _controller!,
        child: Navigator(
          key: widget.navigatorKey,
          restorationScopeId: widget.navigatorRestorationId,
          pages: _pages!,
          observers: widget.observers,
          onPopPage: _handlePopPage,
        ),
      ),
    );
  }
}
