// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import 'dart:async';

import 'package:example_router/core/dependency_injection/get_it.dart';
import 'package:example_router/core/routes/router.dart';
import 'package:example_router/core/utils/custom_password.dart';
import 'package:example_router/presentation/features/authentication/authentication_cubit.dart';
import 'package:example_router/presentation/features/authentication/sign_in/blocs/sign_in_cubit.dart';
import 'package:example_router/presentation/features/authentication/sign_up/blocs/sign_up_cubit.dart';
import 'package:example_router/presentation/features/edit_account/blocs/edit_account_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';

class App extends StatelessWidget {
  final AuthenticationRepository<int> authenticationRepository =
      AuthenticationRepositoryImpl(
    authenticationRemoteDataSource:
        getIt<AuthenticationRemoteDataSource<int>>(),
    authenticationSessionDataSource:
        getIt<AuthenticationSessionDataSource<int>>(),
    authenticationCacheDataSource: getIt<AuthenticationCacheDataSource<int>>(),
    customPasswordValidator: const CustomPassword.pure(),
    extraSignUpInputs: [
      FormInput(
        AuthFormField.confirmPassword,
        const ConfirmedPassword.pure(),
        metadata: const FormInputMetadata<void>(export: false),
      ),
    ],
  );

  App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    AuthenticationState<int>? previous;

    final AuthenticationCubit<int> authenticationCubit =
        ExampleAuthenticationCubit(
            authenticationRepository: authenticationRepository);

    final GoRouter router = GoRouter(
      initialLocation: '/',
      routes: AppRouter.routes,
      debugLogDiagnostics: true,
      errorBuilder: (_, __) => const ColoredBox(
        color: Colors.red,
      ),
      refreshListenable: GoRouterRefreshStream(authenticationCubit.stream),
      redirect: (context, state) {
        final authState = authenticationCubit.state;

        if (authState.status != previous?.status) {
          previous = authState;
          // Checking if current path is onboarding or not
          final isOnboarding = AppRouter.publicRoutes.contains(state.subloc);
          if (authState.status == AuthenticationStatus.unauthenticated) {
            debugPrint('Not logged');
            if (!isOnboarding) {
              return '/';
            }
          } else if (authState.status == AuthenticationStatus.authenticated) {
            debugPrint('Logged');
            return '/home';
          }
        }
        return state.name;
      },
    );

    return MultiRepositoryProvider(
      providers: [
        RepositoryProvider<AuthenticationRepository<int>>.value(
          value: authenticationRepository,
        ),
        RepositoryProvider<FormRepository>(
          create: (context) => FormRepositoryImpl(),
        )
      ],
      child: MultiBlocProvider(
        providers: [
          BlocProvider<AuthenticationCubit<int>>.value(
            value: authenticationCubit,
          ),
          BlocProvider<SignUpCubit<int>>(
            create: (_) => ExampleSignUpCubit(
              authenticationRepository: authenticationRepository,
            ),
          ),
          BlocProvider<SignInCubit<int>>(
            create: (_) => ExampleSignInCubit(
              authenticationRepository: authenticationRepository,
            ),
          ),
          BlocProvider<EditAccountCubit<int>>(
            create: (_) => ExampleEditAccountCubit(
              authenticationRepository: authenticationRepository,
            ),
          ),
        ],
        child: MaterialApp.router(
          title: 'Demo Authentication',
          debugShowCheckedModeBanner: false,
          routerConfig: router,
        ),
      ),
    );
  }
}

class GoRouterRefreshStream extends ChangeNotifier {
  GoRouterRefreshStream(Stream<dynamic> stream) {
    notifyListeners();
    _subscription = stream.asBroadcastStream().listen(
          (dynamic _) => notifyListeners(),
        );
  }

  late final StreamSubscription<dynamic> _subscription;

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}
