// ignore_for_file: curly_braces_in_flow_control_structures, use_build_context_synchronously, unrelated_type_equality_checks

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:hub/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart';
import 'package:hub/features/auth/index.dart';
import 'package:hub/features/backend/index.dart';
import 'package:hub/features/module/data/index.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/internationalization.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/features/local/index.dart';
import 'package:hub/shared/utils/snackbar_util.dart';

abstract class LocalsRemoteDataSource {
  Future<void> linkLocal(BuildContext context);
  Future<bool> checkLocals(BuildContext context);
  Future<bool> processLocals(BuildContext context);
  Future<bool> processProperty(BuildContext context);
  Future<bool> selectLocal(BuildContext context, ApiCallResponse? response);
  Future<bool> detachLocal(BuildContext context);
}

class LocalsRemoteDataSourceImpl implements LocalsRemoteDataSource {
  static final LocalsRemoteDataSourceImpl _instance =
      LocalsRemoteDataSourceImpl._internal();
  factory LocalsRemoteDataSourceImpl() => _instance;
  LocalsRemoteDataSourceImpl._internal();

  @override
  Future<void> linkLocal(BuildContext context) async {
    try {
      final GetLocalsCall callback = PhpGroup.getLocalsCall;
      var response = await callback.call();
      final bool? isError = response.jsonBody['error'];

      if (isError == true) {
        LocalUtil.handleError(context, response.jsonBody['error_msg']);
        return;
      }
      if (response.jsonBody == null) {
        final String errorMsg = FFLocalizations.of(context).getVariableText(
          enText: 'Verify your connection',
          ptText: 'Verifique sua conexão',
        );
        // await DialogUtil.error(context, errorMsg).whenComplete(() async => await  selectLocal(context, response));
        return;
      }

      final List<dynamic> locals = response.jsonBody['locais'] ?? [];
      final bool isEmpty = locals.isEmpty;
      final bool isActive =
          locals.where((local) => local['CLU_STATUS'] != 'B').isNotEmpty;
      final bool isEnable = !isEmpty && isActive;

      if (isEnable) {
        await StorageHelper().set(SecureStorageKey.haveLocal.value, true);
        await StorageHelper().set(SecureStorageKey.isLogged.value, true);
        await WidgetsBinding.instance.endOfFrame;
        await StorageHelper().set(ProfileStorageKey.clientUUID.key, '');
        await StorageHelper().set(ProfileStorageKey.ownerUUID.key, '');
        StorageHelper().context?.go('/homePage');
      }
    } catch (e, s) {
      log(e.toString(), stackTrace: s);
    }
  }

  @override
  Future<bool> processLocals(BuildContext context) async {
    log('() => processLocals');
    try {
      final GetLocalsCall callback = PhpGroup.getLocalsCall;
      final ApiCallResponse response = await callback.call();
      final bool? isError = response.jsonBody['error'];

      if (isError == true) {
        final String errorMsg = response.jsonBody['error_msg'];
        LocalUtil.handleError(context, errorMsg);
        return false;
      }
      if (response.jsonBody == null) {
        final String errorMsg = FFLocalizations.of(context).getVariableText(
          enText: 'Verify your connection',
          ptText: 'Verifique sua conexão',
        );
        // await DialogUtil.error(context, errorMsg).whenComplete(() async => await  selectLocal(context, response));
        return false;
      }

      final List<dynamic> locals = response.jsonBody['locais'].toList() ?? [];
      LocalUtil.logLocalsStatus(locals);

      final bool isActive = LocalUtil.isActive(locals);
      final bool isInactived = await LocalUtil.isInactived(locals);
      final bool isPending = LocalUtil.isPending(locals);
      final bool isUnique = locals.length == 1;
      final bool isBlocked =
          locals.where((local) => local['CLU_STATUS'] == 'B').isNotEmpty;
      final bool isEnabled = isUnique && isActive;
      final bool isDisabled = isUnique && isBlocked;
      final bool isUnselected = await LocalUtil.isUnselected();
      final bool isSelected = await LocalUtil.isSelected(isInactived);
      final bool isUnavailable = isPending && isUnselected && isUnique;
      final bool isAvailable = await LocalUtil.isAvailable();

      if (isDisabled) {
        AuthenticationService.signOut(context);
        return true;
      } else if (isUnavailable) {
        return await selectLocal(context, response);
      } else if (isEnabled) {
        return await LocalUtil.handleEnabled(context, locals[0]);
      } else if (isUnselected) {
        log('() => isUnselected');
        return await selectLocal(context, response);
      } else if (isSelected) {
        log('() => isSelected');
        return await processProperty(context).then((v) async {
          if (v == true) return await LicenseRepositoryImpl().updateLicense();
          return v;
        });
      } else if (isAvailable) {
        log('() => isAvailable');
        return await processProperty(context).then((v) async {
          if (v == true) return await LicenseRepositoryImpl().updateLicense();
          return v;
        });
      } else {
        if (!isUnique && !isActive) log('() => not unique and not active');
        if (!isUnique && isInactived) log('() => not unique and inactived');
        if (!isUnique && isPending) log('() => not unique and pending');
        if (!isUnique && isBlocked) log('() => not unique and blocked');
        log('() => else');
        return await selectLocal(context, response);
      }
    } catch (e, s) {
      log('() => stack: $s');
      log('() => catch: $e', stackTrace: s);
      // return await selectLocal(context);
      final String errorMsg = FFLocalizations.of(context).getVariableText(
        enText: 'Error getting locals, verify your connection',
        ptText: 'Erro ao obter locais, verifique sua conexão',
      );
      // await DialogUtil.error(context, errorMsg).whenComplete(() async => await  selectLocal(context, null));
      return false;
    }
  }

  @override
  Future<bool> checkLocals(BuildContext context) async {
    final String? cliUUID =
        await StorageHelper().get(ProfileStorageKey.clientUUID.key);
    final String? cliName =
        await StorageHelper().get(ProfileStorageKey.clientName.key);
    final haveCli = cliUUID != null && cliUUID.isNotEmpty;
    final haveName = cliName != null && cliName.isNotEmpty;
    return haveCli && haveName;
  }

  @override
  Future<bool> processProperty(BuildContext context) async {
    try {
      final GetDadosCall callback = PhpGroup.getDadosCall;
      ApiCallResponse? response = await callback.call();
      if (response.jsonBody == null) {
        final GetLocalsCall callback = PhpGroup.getLocalsCall;
        response = await callback.call();
        final String errorMsg = FFLocalizations.of(context).getVariableText(
          enText: 'Verify your connection',
          ptText: 'Verifique sua conexão',
        );
        // await DialogUtil.error(context, errorMsg).whenComplete(() async => await  selectLocal(context, response));
        return false;
      }

      final bool? isError = response.jsonBody['error'];
      if (isError == true) {
        final GetLocalsCall callback = PhpGroup.getLocalsCall;
        response = await callback.call();
        final String errorMsg =
            response.jsonBody['error_msg'] ?? 'Local indisponível';
        // await DialogUtil.error(context, errorMsg).whenComplete(() async => await selectLocal(context, response));
        return false;
      } else {
        await LocalUtil.updateStorageUtil(response.jsonBody);
        return true;
      }
    } catch (e, s) {
      log('() => error processData: $e', stackTrace: s);
      final String errorMsg = FFLocalizations.of(context).getVariableText(
        enText: 'Error getting data, verify your connection',
        ptText: 'Erro ao obter dados, verifique sua conexão',
      );
      // await DialogUtil.error(context, errorMsg).whenComplete(() async => await selectLocal(context, null));
      return false;
    }
  }

  @override
  Future<bool> selectLocal(
      BuildContext context, ApiCallResponse? response) async {
    return await showModalBottomSheet(
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      enableDrag: false,
      isDismissible: false,
      showDragHandle: false,
      useSafeArea: true,
      context: context,
      builder: (context) => PopScope(
        canPop: false,
        child: Padding(
          padding: MediaQuery.viewInsetsOf(context),
          child: BottomArrowLinkedLocalsComponentWidget(response: response),
        ),
      ),
    ).then((_) async => await processProperty(context).then((v) async {
          if (v == true) return await LicenseRepositoryImpl().updateLicense();
          return v;
        }));
  }

  @override
  Future<bool> detachLocal(BuildContext context) async {
    String content;
    try {
      content = FFLocalizations.of(context).getVariableText(
        enText: 'Device unlinked successfully',
        ptText: 'Dispositivo desvinculado com sucesso',
      );
      final bool status =
          await PhpGroup.resopndeVinculo.call(tarefa: 'I').then((value) async {
        if (value.jsonBody['error'] == false) {
          await StorageHelper().set(ProfileStorageKey.clientName.key, '');
          await StorageHelper().set(ProfileStorageKey.ownerName.key, '');
          await StorageHelper().set(ProfileStorageKey.clientUUID.key, '');
          context.pop();
          context.go('/homePage',
              extra: {'update': LocalsRepositoryImpl().update});
          SnackBarUtil.showSnackBar(context, content);
          return true;
        }
        return false;
      }).catchError((err, stack) {
        context.pop();
        content = FFLocalizations.of(context).getVariableText(
          enText: 'Error unlinking device',
          ptText: 'Erro ao desvincular dispositivo',
        );
        SnackBarUtil.showSnackBar(context, content, isError: true);
        return false;
      });
      return status;
    } catch (err, stack) {
      context.pop();
      log(err.toString(), stackTrace: stack);
      content = FFLocalizations.of(context).getVariableText(
        enText: 'Error unlinking device',
        ptText: 'Erro ao desvincular dispositivo',
      );
      SnackBarUtil.showSnackBar(context, content, isError: true);
      return false;
    }
  }
}
