import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

import '../../features/admin/presentation/admin_shell.dart';
import '../../features/admin/presentation/brackets/admin_bracket_form_screen.dart';
import '../../features/admin/presentation/brackets/admin_brackets_screen.dart';
import '../../features/admin/presentation/events/admin_event_form_screen.dart';
import '../../features/admin/presentation/events/admin_events_screen.dart';
import '../../features/admin/presentation/pending/admin_pending_screen.dart';
import '../../features/admin/presentation/suggestions/admin_suggestions_screen.dart';
import '../../features/admin/presentation/teams/admin_team_form_screen.dart';
import '../../features/admin/presentation/teams/admin_teams_screen.dart';
import '../../features/auth/application/auth_notifier.dart';
import '../../features/auth/presentation/login_screen.dart';
import '../../features/auth/presentation/register_screen.dart';
import '../../features/brackets/presentation/bracket_detail_screen.dart';
import '../../features/brackets/presentation/brackets_screen.dart';
import '../../features/events/presentation/event_detail_screen.dart';
import '../../features/events/presentation/events_screen.dart';
import '../../features/media/presentation/media_screen.dart';
import '../../features/profile/application/profile_notifier.dart';
import '../../features/profile/domain/user_profile.dart';
import '../../features/profile/presentation/manager_dashboard_screen.dart';
import '../../features/profile/presentation/my_profile_screen.dart';
import '../../features/profile/presentation/player_profile_screen.dart';
import '../../features/stats/presentation/stats_screen.dart';
import '../../features/suggestions/presentation/suggestions_screen.dart';
import '../../features/teams/presentation/create_team_screen.dart';
import '../../features/teams/presentation/team_detail_screen.dart';
import '../../features/teams/presentation/teams_screen.dart';
import '../admin/admin_guard.dart';
import '../shell/main_shell.dart';

/// Routes that an unauthenticated user is allowed to visit. Anything else
/// triggers a redirect to `/login`. Player profile pages stay reachable to
/// signed-out viewers so shared links work.
const _publicRoutes = {'/login', '/register'};

/// Path prefixes that anonymous viewers may visit even without a session.
/// Player profile pages are intentionally readable so a roster link shared
/// outside the app still works.
const _viewerPrefixes = <String>['/players/'];

final appRouterProvider = Provider<GoRouter>((ref) {
  // GoRouter listens to this notifier and re-evaluates `redirect` whenever
  // it fires — we ping it on every auth state change.
  final refresh = _AuthRouterRefresh(ref);
  ref.onDispose(refresh.dispose);

  return GoRouter(
    initialLocation: '/events',
    refreshListenable: refresh,
    redirect: (context, state) {
      final auth = ref.read(authNotifierProvider);

      // Don't redirect while the initial auth check is still loading —
      // GoRouter will re-run this once the notifier has data.
      if (auth.isLoading || !auth.hasValue) return null;

      final user = auth.value;
      final location = state.matchedLocation;
      final isPublic = _publicRoutes.contains(location);
      final isViewerOk = _viewerPrefixes.any(location.startsWith);
      final isAdminRoute = location.startsWith('/admin');
      final isManagerRoute = location == '/manager';

      if (user == null && !isPublic && !isViewerOk) {
        return '/login';
      }
      if (user != null && isPublic) {
        return '/events';
      }
      if (isAdminRoute && !isAdmin(user)) {
        return '/events';
      }
      if (isManagerRoute) {
        // Manager dashboard is reserved for users with the manager role
        // (admins also fall through — they have their own panel).
        final role = ref.read(currentUserRoleProvider);
        if (role != UserRole.manager) {
          return '/events';
        }
      }
      return null;
    },
    routes: [
      GoRoute(path: '/login', builder: (context, state) => const LoginScreen()),
      GoRoute(
        path: '/register',
        builder: (context, state) => const RegisterScreen(),
      ),
      ShellRoute(
        builder: (context, state, child) => MainShell(child: child),
        routes: [
          GoRoute(
            path: '/events',
            builder: (context, state) => const EventsScreen(),
            routes: [
              GoRoute(
                path: ':id',
                builder: (context, state) =>
                    EventDetailScreen(eventId: state.pathParameters['id']!),
              ),
            ],
          ),
          GoRoute(
            path: '/brackets',
            builder: (context, state) => const BracketsScreen(),
            routes: [
              GoRoute(
                path: ':id',
                builder: (context, state) =>
                    BracketDetailScreen(bracketId: state.pathParameters['id']!),
              ),
            ],
          ),
          GoRoute(
            path: '/teams',
            builder: (context, state) => const TeamsScreen(),
            routes: [
              GoRoute(
                path: 'new',
                builder: (context, state) => const CreateTeamScreen(),
              ),
              GoRoute(
                path: ':id',
                builder: (context, state) =>
                    TeamDetailScreen(teamId: state.pathParameters['id']!),
              ),
            ],
          ),
          GoRoute(
            path: '/stats',
            builder: (context, state) => const StatsScreen(),
          ),
          GoRoute(
            path: '/media',
            builder: (context, state) => const MediaScreen(),
          ),
          GoRoute(
            path: '/suggestions',
            builder: (context, state) => const SuggestionsScreen(),
          ),
          GoRoute(
            path: '/profile',
            builder: (context, state) => const MyProfileScreen(),
          ),
          GoRoute(
            path: '/players/:uid',
            builder: (context, state) =>
                PlayerProfileScreen(uid: state.pathParameters['uid']!),
          ),
          GoRoute(
            path: '/manager',
            builder: (context, state) => const ManagerDashboardScreen(),
          ),
        ],
      ),
      ShellRoute(
        builder: (context, state, child) => AdminShell(child: child),
        routes: [
          GoRoute(
            path: '/admin/events',
            builder: (context, state) => const AdminEventsScreen(),
          ),
          GoRoute(
            path: '/admin/events/new',
            builder: (context, state) => const AdminEventFormScreen(),
          ),
          GoRoute(
            path: '/admin/events/:id/edit',
            builder: (context, state) =>
                AdminEventFormScreen(eventId: state.pathParameters['id']),
          ),
          GoRoute(
            path: '/admin/teams',
            builder: (context, state) => const AdminTeamsScreen(),
          ),
          GoRoute(
            path: '/admin/teams/new',
            builder: (context, state) => const AdminTeamFormScreen(),
          ),
          GoRoute(
            path: '/admin/teams/:id/edit',
            builder: (context, state) =>
                AdminTeamFormScreen(teamId: state.pathParameters['id']),
          ),
          GoRoute(
            path: '/admin/brackets',
            builder: (context, state) => const AdminBracketsScreen(),
          ),
          GoRoute(
            path: '/admin/brackets/new',
            builder: (context, state) => const AdminBracketFormScreen(),
          ),
          GoRoute(
            path: '/admin/brackets/:id/edit',
            builder: (context, state) =>
                AdminBracketFormScreen(bracketId: state.pathParameters['id']),
          ),
          GoRoute(
            path: '/admin/suggestions',
            builder: (context, state) => const AdminSuggestionsScreen(),
          ),
          GoRoute(
            path: '/admin/pending',
            builder: (context, state) => const AdminPendingScreen(),
          ),
        ],
      ),
    ],
  );
});

/// Bridges the Riverpod auth notifier (and the derived role provider) to a
/// [ChangeNotifier] that GoRouter can subscribe to via `refreshListenable`.
/// Sign-in/out and role changes both ping GoRouter to re-run `redirect`.
class _AuthRouterRefresh extends ChangeNotifier {
  _AuthRouterRefresh(this._ref) {
    _authSub = _ref.listen<AsyncValue>(
      authNotifierProvider,
      (prev, next) => notifyListeners(),
      fireImmediately: false,
    );
    _roleSub = _ref.listen<UserRole>(
      currentUserRoleProvider,
      (prev, next) {
        if (prev != next) notifyListeners();
      },
      fireImmediately: false,
    );
  }

  final Ref _ref;
  late final ProviderSubscription<AsyncValue> _authSub;
  late final ProviderSubscription<UserRole> _roleSub;

  @override
  void dispose() {
    _authSub.close();
    _roleSub.close();
    super.dispose();
  }
}
