import '../../../../model/passo/barangay.dart';
import '../../../../model/passo/city.dart';
import '../../../../model/passo/class_components _offline.dart';
import '../../../../model/passo/class_components.dart';
import '../../../../model/passo/land_classification.dart';
import '../../../../model/passo/land_subclassification.dart';
import '../../../../model/passo/land_value_adjustment.dart';
import '../../../../model/passo/memoranda.dart';
import '../../../../model/passo/signatories.dart';
import '../../../../model/passo/trees_improvements.dart';
import '../../../../model/passo/type_of_location.dart';
import '../../../../model/passo/type_of_road.dart';
import '../../../../model/passo/unit_construct.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/barangay_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/class_components_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/land_classification_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/land_sub_classification_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/memoranda_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/municipalities_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/signatories.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/trees_improvements_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/type_of_location.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/type_of_road_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/unit_construction_api_services.dart';
import '../../../../sevices/offline/offline_passo/admin/api_services/value_adjustments.dart';
import '../../../../sevices/offline/offline_passo/admin/sql_services/sql_services.dart';

class GlobalSyncService {
  static final GlobalSyncService _instance = GlobalSyncService._internal();

  factory GlobalSyncService() {
    return _instance;
  }

  GlobalSyncService._internal();

  Future<void> syncAllData() async {
    const maxRetries = 100;
    int retryCount = 0;

    // Helper function for retrying individual sync methods
    Future<void> syncWithRetry(Future<void> Function() syncMethod) async {
      if (retryCount < maxRetries) {
        retryCount++;
        print('Retrying synchronization for ${retryCount}...');
        // Implement a backoff strategy, for example, using a delay.
        await Future.delayed(Duration(seconds: retryCount * 2));
        await syncMethod();
      } else {
        print('Max retries reached for ${syncMethod.toString()}. Sync failed.');
        // Handle the failure as needed (e.g., show an error message).
      }
    }

    Future<void> retrySync() async {
      try {
        await syncWithRetry(syncBrgyData);
        await syncWithRetry(syncClassComponentsData);
        await syncWithRetry(syncLandClassification);
        await syncWithRetry(syncLandSubClassification);
        await syncWithRetry(syncMemoranda);
        await syncWithRetry(syncMunicipalities);
        await syncWithRetry(syncSignatories);
        await syncWithRetry(syncTreesImprovements);
        await syncWithRetry(syncTypeOfLocation);
        await syncWithRetry(syncTypeOfRoad);
        await syncWithRetry(syncUnitConstruct);
        await syncWithRetry(syncValueAdjustment);
      } catch (e) {
        print(e);
        print('Max retries reached. Sync failed.');
        // Handle the failure as needed (e.g., show an error message).
      }
    }

    await retrySync();
    // Add more sync methods as needed
  }

  Future<void> syncBrgyData() async {
    final result = await BrgyAdminApiServices.instance.fetch();
    final brgys = result.map((json) => Brgy.fromJson(json)).toList();

    for (Brgy brgy in brgys) {
      await SQLServices.instance.createBarangay(brgy);
    }
  }

  Future<void> syncClassComponentsData() async {
    final result = await ClassComponentAdminApiServices.instance.fetch();
    final classes =
        result.map((json) => ClassComponents.fromJson(json)).toList();

    for (ClassComponents classs in classes) {
      await SQLServices.instance.createClassComponents(
        ClassComponentsOffline(
            componentName: classs.componentName,
            minBaseUnitvalPercent: classs.minBaseUnitvalPercent,
            maxBaseUnitvalPercent: classs.maxBaseUnitvalPercent,
            minUnitvalSqrmtr: classs.minUnitvalSqrmtr,
            maxUnitvalSqrmtr: classs.maxUnitvalSqrmtr,
            minAddBaseunitval: classs.minAddBaseunitval,
            maxAddBaseunitval: classs.maxAddBaseunitval,
            minDeductBaserate: classs.minAddBaseunitval,
            maxDeductBaserate: classs.maxDeductBaserate,
            minLinearMeter: classs.minLinearMeter,
            maxLinearMeter: classs.maxLinearMeter,
            minSpacing: classs.minSpacing,
            maxSpacing: classs.maxSpacing,
            roughFinish: classs.roughFinish,
            highFinish: classs.highFinish,
            withoutBucc: classs.withoutBucc == true ? 1 : 0),
      );
    }
  }

  Future<void> syncLandClassification() async {
    final result = await LandClassificationAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final landClass =
        result.map((json) => LandClassification.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (LandClassification landClassification in landClass) {
      await SQLServices.instance.createLandClassification(landClassification);
    }
  }

  Future<void> syncLandSubClassification() async {
    final result = await LandSubClassificationAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final landSubClass =
        result.map((json) => LandSubClassification.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (LandSubClassification landSubClassification in landSubClass) {
      await SQLServices.instance
          .createLandSubClassification(landSubClassification);
    }
  }

  Future<void> syncMemoranda() async {
    final result = await MemorandaAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final memos = result.map((json) => Memoranda.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (Memoranda memo in memos) {
      await SQLServices.instance.createMemoranda(memo);
    }
  }

  Future<void> syncMunicipalities() async {
    final result = await MunicipalityAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final cities = result.map((json) => City.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (City city in cities) {
      print(city.cityDescription);
      print(city.cityCode);
      await SQLServices.instance.createMunicipalities(city);
    }
  }

  Future<void> syncSignatories() async {
    final result = await SignatoriesAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final signatories =
        result.map((json) => Signatories.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (Signatories signatory in signatories) {
      await SQLServices.instance.createSignatories(signatory);
    }
  }

  Future<void> syncTreesImprovements() async {
    final result = await TreesImprovementsAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final treesImpr =
        result.map((json) => TreesImprovements.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (TreesImprovements treesImprovements in treesImpr) {
      await SQLServices.instance.createTreesImprovements(treesImprovements);
    }
  }

  Future<void> syncTypeOfLocation() async {
    final result = await TypeOfLocationAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final typesOfLoc =
        result.map((json) => TypeOfLocation.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (TypeOfLocation typesOfLocation in typesOfLoc) {
      await SQLServices.instance.createTypeOfLocation(typesOfLocation);
    }
  }

  Future<void> syncTypeOfRoad() async {
    final result = await TypeOfRoadAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final typesOfRoad =
        result.map((json) => TypeOfRoad.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (TypeOfRoad typesOfRoad in typesOfRoad) {
      await SQLServices.instance.createTypeOfRoad(typesOfRoad);
    }
  }

  Future<void> syncUnitConstruct() async {
    final result = await UnitConstructionAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final units = result.map((json) => UnitConstruct.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (UnitConstruct unit in units) {
      await SQLServices.instance.createUnitConstruction(unit);
    }
  }

  Future<void> syncValueAdjustment() async {
    final result = await ValueAdjustmentsAdminApiServices.instance.fetch();

    // Assuming result is a List of JSON objects, convert them to City objects.
    final valueAdj =
        result.map((json) => ValueAdjustments.fromJson(json)).toList();

    // Loop through the list of City objects and insert them into the local database.
    for (ValueAdjustments valueAdjustments in valueAdj) {
      await SQLServices.instance.createValueAdjustments(valueAdjustments);
    }
  }
}
