// 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:http/src/response.dart';
import 'package:hub/backend/api_requests/api_manager.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/shared/helpers/base_storage.dart';
import 'package:hub/shared/helpers/storage_helper.dart';
import 'package:hub/shared/utils/device_util.dart';
import 'package:hub/shared/utils/dialog_util.dart';

import '../../../backend/api_requests/api_calls.dart';
import '../../../components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart';
import '../../../flutter_flow/flutter_flow_util.dart';
import '../../utils/log_util.dart';
import '../../utils/snackbar_util.dart';
import '../authentication/authentication_service.dart';

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

      if (isError == true) {
        _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(() => 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', Storage.SecureStorage);
        await StorageHelper().set(SecureStorageKey.isLogged.value, 'true', Storage.SecureStorage);
        await WidgetsBinding.instance.endOfFrame;
        await StorageHelper().set(SQLiteStorageKey.clientUUID.value, '', Storage.SQLiteStorage);
        await StorageHelper().set(SQLiteStorageKey.ownerUUID.value, '', Storage.SQLiteStorage);
        StorageHelper().context?.go('/homePage');
      }
    } catch (e, s) {
      log(e.toString(), stackTrace: s);
    }
  }

  static Future<bool> processLocals(BuildContext context) async {
    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'];
        _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(() => selectLocal(context, response));
        return false;
      }

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

      final bool isActive = _isActive(locals);
      final bool isInactived = await _isInactived(locals);
      final bool isPending = _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 _isUnselected();
      final bool isSelected = await _isSelected(isInactived);
      final bool isUnavailable = isPending && isUnselected && isUnique;
      final bool isAvailable = await _isAvailable();

      if (isDisabled) {
        AuthenticationService.signOut(context);
        return true;
      } else if (isUnavailable) {
        return await _handleUnavailable(context, locals);
      } else if (isEnabled) {
        return await _handleEnabled(context, locals[0]);
      } else if (isUnselected) {
        log('() => isUnselected');
        return await selectLocal(context, response);
      } else if (isSelected) {
        log('() => isSelected');
        return await processData(context);
      } else if (isAvailable) {
        log('() => isAvailable');
        return await processData(context);
      } 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(() => selectLocal(context, null));
      return false;
    }
  }

  static Future<bool> processData(BuildContext context) async {
    try {
      final GetDadosCall callback = PhpGroup.getDadosCall;
      ApiCallResponse? response = await callback.call();
      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'];
        await DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context, response));
        return false;
      } else 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(() => selectLocal(context, response));
        return false;
      } else {
        await _updateStorageUtil(response.jsonBody);
        return true;
      }
    } catch (e, s) {
      log('() => stack processData: $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(() => selectLocal(context, null));
      return false;
    }
  }

  static 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 processData(context));
  }

  static Future<void> unlinkLocal(BuildContext context) async {
    String content;
    try {
      content = FFLocalizations.of(context).getVariableText(
        enText: 'Device unlinked successfully',
        ptText: 'Dispositivo desvinculado com sucesso',
      );

      await PhpGroup.resopndeVinculo.call(tarefa: 'I').then((value) async {
        if (value.jsonBody['error'] == false) {
          await StorageHelper().set(SQLiteStorageKey.clientName.value, '', Storage.SQLiteStorage);
          await StorageHelper().set(SQLiteStorageKey.clientUUID.value, '', Storage.SQLiteStorage);
          context.pop();
          context.go(
            '/homePage',
            extra: <String, dynamic>{
              kTransitionInfoKey: const TransitionInfo(
                hasTransition: true,
                transitionType: PageTransitionType.scale,
                alignment: Alignment.bottomCenter,
              ),
            },
          );
          SnackBarUtil.showSnackBar(context, content);
        }
      }).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);
      });
    } 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);
    }
  }

  static void _handleError(BuildContext context, String errorMsg) async {
    final String devUUID = await StorageHelper().get(SQLiteStorageKey.devUUID.value, Storage.SQLiteStorage) ?? '';
    final String userUUID = await StorageHelper().get(SQLiteStorageKey.userUUID.value, Storage.SQLiteStorage) ?? '';
    final bool isAuthenticated = userUUID.isNotEmpty && devUUID.isNotEmpty;
    final bool isDevLinked = !errorMsg.contains('Esse dispositivo nao pertence a esse usuario');
    log('() => isLinked: $errorMsg');
    log('() => isLinked: $errorMsg');
    if (!isAuthenticated) {
      errorMsg = FFLocalizations.of(context).getVariableText(
        ptText: 'Erro ao obter credenciais de autenticação',
        enText: 'Error getting authentication credentials',
      );
      await DialogUtil.error(context, errorMsg);
      return;
      // await DialogUtil.error(context, errorMsg).whenComplete(() async => await AuthenticationService.signOut(context));
    }
    if (!isDevLinked) {
      errorMsg = FFLocalizations.of(context).getVariableText(
        ptText: 'Não foi possível vincular o dispositivo, tente novamente.',
        enText: 'Unable to link device, try again',
      );
      await DialogUtil.warning(context, errorMsg);
      return;
    }
    await DialogUtil.error(context, errorMsg).whenComplete(() async => await selectLocal(context, null));
  }

  static Future<bool> _handleUnavailable(BuildContext context, List<dynamic> locals) async {
    log('() => isUnavailable');
    try {
      await StorageHelper().set(SQLiteStorageKey.clientUUID.value, locals[0]['CLI_ID'], Storage.SQLiteStorage);
      await StorageHelper().set(SQLiteStorageKey.ownerUUID.value, locals[0]['CLU_OWNER_ID'], Storage.SQLiteStorage);
      await StorageHelper().set(SQLiteStorageKey.clientName.value, locals[0]['CLI_NOME'], Storage.SQLiteStorage);
      var response = await PhpGroup.resopndeVinculo.call(tarefa: 'A');
      if (response.jsonBody['error'] == true) {
        await StorageHelper().set(SQLiteStorageKey.clientUUID.value, '', Storage.SQLiteStorage);
        await StorageHelper().set(SQLiteStorageKey.ownerUUID.value, '', Storage.SQLiteStorage);
        await StorageHelper().set(SQLiteStorageKey.clientName.value, '', Storage.SQLiteStorage);
        return false;
      }
      if (response.jsonBody['error'] == false) return await processData(context).then((value) => value);
    } catch (e, s) {
      await DialogUtil.errorDefault(context);
      LogUtil.requestAPIFailed('responderVinculo.php', '', 'Responder Vínculo', e, s);
      return false;
    }
    return false;
  }

  static Future<bool> _handleEnabled(BuildContext context, dynamic local) async {
    log('() => isEnabled');
    await StorageHelper().set(SQLiteStorageKey.clientUUID.value, local['CLI_ID'], Storage.SQLiteStorage);
    await StorageHelper().set(SQLiteStorageKey.ownerUUID.value, local['CLU_OWNER_ID'], Storage.SQLiteStorage);
    await StorageHelper().set(SQLiteStorageKey.clientName.value, local['CLI_NOME'], Storage.SQLiteStorage);
    await StorageHelper().set(SQLiteStorageKey.userName.value, local['USU_NOME'], Storage.SQLiteStorage);
    return await processData(context);
  }

  static void _logLocalsStatus(List<dynamic> locals) {
    for (var local in locals) {
      final String status = local['CLU_STATUS'];
      log('() => CLU_STATUS: $status');
    }
  }

  static bool _isActive(List<dynamic> locals) {
    return locals.where((local) => local['CLU_STATUS'] == 'A').isNotEmpty;
  }

  static Future<bool> _isInactived(List<dynamic> locals) async {
    String cliUUID = (await StorageHelper().get(SQLiteStorageKey.clientUUID.value, Storage.SQLiteStorage)) ?? '';
    return locals.where((local) => local['CLI_ID'] != cliUUID && local['CLU_STATUS'] == 'A').isNotEmpty;
  }

  static bool _isPending(List<dynamic> locals) {
    return locals.where((local) => local['CLU_STATUS'] != 'B' && local['CLU_STATUS'] != 'A').isNotEmpty;
  }

  static Future<bool> _isUnselected() async {
    String cliUUID = (await StorageHelper().get(SQLiteStorageKey.clientUUID.value, Storage.SQLiteStorage)) ?? '';
    String cliName = (await StorageHelper().get(SQLiteStorageKey.clientName.value, Storage.SQLiteStorage)) ?? '';
    String ownerUUID = (await StorageHelper().get(SQLiteStorageKey.ownerUUID.value, Storage.SQLiteStorage)) ?? '';
    return cliUUID.isEmpty && cliName.isEmpty && ownerUUID.isEmpty;
  }

  static Future<bool> _isSelected(bool isInactived) async {
    String cliUUID = (await StorageHelper().get(SQLiteStorageKey.clientUUID.value, Storage.SQLiteStorage)) ?? '';
    String cliName = (await StorageHelper().get(SQLiteStorageKey.clientName.value, Storage.SQLiteStorage)) ?? '';
    return cliUUID.isNotEmpty && cliName.isNotEmpty && isInactived;
  }

  static Future<bool> _isAvailable() async {
    String cliUUID = (await StorageHelper().get(SQLiteStorageKey.clientUUID.value, Storage.SQLiteStorage)) ?? '';
    String cliName = (await StorageHelper().get(SQLiteStorageKey.clientName.value, Storage.SQLiteStorage)) ?? '';
    return cliUUID.isNotEmpty && cliName.isNotEmpty;
  }

  static Future<void> _updateStorageUtil(Map<String, dynamic> jsonBody) async {
    await StorageHelper().set(SQLiteStorageKey.whatsapp.value,
        jsonBody['whatsapp'] != null && jsonBody['whatsapp'] ? 'true' : 'false', Storage.SQLiteStorage);
    await StorageHelper().set(SQLiteStorageKey.provisional.value,
        jsonBody['provisional'] != null && jsonBody['provisional'] ? 'true' : 'false', Storage.SQLiteStorage);
    await StorageHelper().set(SQLiteStorageKey.pets.value,
        jsonBody['pet'] != null && jsonBody['pet'] ? 'true' : 'false', Storage.SQLiteStorage);
    await StorageHelper().set(
        SQLiteStorageKey.petAmount.value,
        jsonBody['petAmountRegister'] != null && jsonBody['petAmountRegister'].toString().isEmpty
            ? '0'
            : jsonBody['petAmountRegister'].toString(),
        Storage.SQLiteStorage);
    await StorageHelper().set(SQLiteStorageKey.userName.value, jsonBody['visitado']['VDO_NOME'], Storage.SQLiteStorage);
  }
}
