import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependency_injection.dart';
import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart';
import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/user_models/cities.dart';
import 'package:mc_common_app/models/user_models/country.dart';
import 'package:mc_common_app/models/user_models/role.dart';
import 'package:mc_common_app/utils/utils.dart';

abstract class CommonRepo {
  Future<Country> getAllCountries();

  Future<List<VehicleTypeModel>> getVehicleTypes();

  Future<List<VehicleBrandsModel>> getVehicleBrands({required int vehicleTypeId});

  Future<List<VehicleModel>> getVehicleModels({required int vehicleTypeId});

  Future<List<VehicleYearModel>> getVehicleModelYears({required int vehicleTypeId});

  Future<List<VehicleColorModel>> getVehicleColors({required int vehicleTypeId});

  Future<List<VehicleConditionModel>> getVehicleConditions({required int vehicleTypeId});

  Future<List<VehicleCategoryModel>> getVehicleCategories({required int vehicleTypeId});

  Future<List<VehicleMileageModel>> getVehicleMileages({required int vehicleTypeId});

  Future<List<VehicleTransmissionModel>> getVehicleTransmission({required int vehicleTypeId});

  Future<List<VehicleSellerTypeModel>> getVehicleSellerTypes({required int vehicleTypeId});

  Future<List<VehicleCountryModel>> getVehicleCountries();

  Future<List<VehicleCityModel>> getVehicleCities({required int countryId});

  Future<List<VehiclePartModel>> getVehicleDamageParts();

  Future<Cities> getAllCites(String countryId);

  Future<Role> getRoles();

  Future<SSCarCheckScheduleModel> getCarCheckServiceScheduleDetails({required double lat, required double long});

  Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long, required int cityID});

  //TODO: Needs to remove common methods from AD's repo and delete all repeated methods.
  Future<VehicleDetailsModel> getVehicleDetails({int? vehicleTypeId, int? vehicleBrandId});

  Future<List<EnumsModel>> getEnumTypeValues({int? enumTypeID, String? enumTypeName});

  Future<GenericRespModel> createComplainFromProvider({required int customerId, required String comment, required int complainType});
}

class CommonRepoImp implements CommonRepo {
  ApiClient apiClient = injector.get<ApiClient>();
  AppState appState = injector.get<AppState>();

  @override
  Future<Country> getAllCountries() async {
    return await apiClient.getJsonForObject((json) => Country.fromJson(json), ApiConsts.getAllCountry);
  }

  @override
  Future<Cities> getAllCites(String countryId) async {
    var postParams = {
      "CountryID": countryId,
    };
    return await apiClient.getJsonForObject((json) => Cities.fromJson(json), ApiConsts.getAllCities, queryParameters: postParams);
  }

  @override
  Future<Role> getRoles() async {
    return await apiClient.getJsonForObject((json) => Role.fromJson(json), ApiConsts.getProviderRoles);
  }

  @override
  Future<SSCarCheckScheduleModel> getCarCheckServiceScheduleDetails({required double lat, required double long}) async {
    var params = {
      "Latitude": lat.toString(),
      "Longitude": long.toString(),
    };
    GenericRespModel genericRespModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      queryParameters: params,
      ApiConsts.adsCarCheckupSPBranchScheduleSlotGet,
    );
    SSCarCheckScheduleModel ssCarCheckScheduleModel = SSCarCheckScheduleModel.fromJson(genericRespModel.data[0]);
    return ssCarCheckScheduleModel;
  }

  @override
  Future<List<SSPhotoOfficeScheduleModel>> getPhotographyServiceScheduleListByOffices({required double lat, required double long, required int cityID}) async {
    var params = {
      "Latitude": lat.toString(),
      "Longitude": long.toString(),
      "cityID": cityID.toString(),
    };
    GenericRespModel genericRespModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      queryParameters: params,
      ApiConsts.adsPhotoOfficeAppointmentScheduleSlotGet,
    );
    if (genericRespModel.data == null) {
      return [];
    }
    List<SSPhotoOfficeScheduleModel> ssPhotoScheduleModel = List.generate(genericRespModel.data.length, (index) => SSPhotoOfficeScheduleModel.fromJson(genericRespModel.data[index]));
    return ssPhotoScheduleModel ?? [];
  }

  @override
  Future<List<VehicleTypeModel>> getVehicleTypes() async {
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleTypeGet);
    List<VehicleTypeModel> vehicleTypes = List.generate(adsGenericModel.data.length, (index) => VehicleTypeModel.fromJson(adsGenericModel.data[index]));
    return vehicleTypes;
  }

  @override
  Future<List<EnumsModel>> getEnumTypeValues({int? enumTypeID, String? enumTypeName}) async {
    if (enumTypeID == -1) {
      // This is for the vehicle type condition (old, new) which will be added to API later
      final Map<String, dynamic> json = {
        "data": [
          {"id": 1, "enumTypeID": 0, "enumValueStr": "New", "enumValue": 1, "isActive": true},
          {"id": 2, "enumTypeID": 0, "enumValueStr": "Used", "enumValue": 2, "isActive": true},
        ],
      };

      List<EnumsModel> enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index]));
      return enums;
    }

    if (enumTypeID == -2) {
      // This is for the ShippingRequestStatus which will be added to API later
      final Map<String, dynamic> json = {
        "data": [
          {"id": 1, "enumTypeID": 0, "enumValueStr": "Initiated", "enumValue": 1, "isActive": true},
          {"id": 2, "enumTypeID": 0, "enumValueStr": "In Transit", "enumValue": 2, "isActive": true},
          {"id": 3, "enumTypeID": 0, "enumValueStr": "Out for Delivery", "enumValue": 3, "isActive": true},
          {"id": 4, "enumTypeID": 0, "enumValueStr": "Delivered", "enumValue": 4, "isActive": true},
        ],
      };

      List<EnumsModel> enums = List.generate((json['data'] as List).length, (index) => EnumsModel.fromJson(json['data'][index]));
      return enums;
    }
    var postParams = {"enumTypeID": (enumTypeID ?? 0).toString(), "enumTypeName": enumTypeName ?? ""};
    GenericRespModel enumGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.getEnumTypeValues,
      postParams,
      token: appState.getUser.data!.accessToken,
    );

    List<EnumsModel> enums = List.generate(enumGenericModel.data.length, (index) => EnumsModel.fromJson(enumGenericModel.data[index]));
    return enums;
  }

  @override
  Future<List<VehicleCategoryModel>> getVehicleCategories({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel =
        await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCategoryGet, queryParameters: postParams);
    List<VehicleCategoryModel> vehicleCategories = List.generate(adsGenericModel.data.length, (index) => VehicleCategoryModel.fromJson(adsGenericModel.data[index]));
    return vehicleCategories;
  }

  @override
  Future<List<VehicleCityModel>> getVehicleCities({required int countryId}) async {
    var postParams = {
      "CountryID": countryId.toString(),
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
        token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCityGet, queryParameters: countryId != -1 ? postParams : null);
    List<VehicleCityModel> vehicleCities = List.generate(adsGenericModel.data.length, (index) => VehicleCityModel.fromJson(adsGenericModel.data[index]));
    return vehicleCities;
  }

  @override
  Future<List<VehicleColorModel>> getVehicleColors({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel =
        await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleColorGet, queryParameters: postParams);
    List<VehicleColorModel> vehicleColors = List.generate(adsGenericModel.data.length, (index) => VehicleColorModel.fromJson(adsGenericModel.data[index]));
    return vehicleColors;
  }

  @override
  Future<List<VehicleConditionModel>> getVehicleConditions({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel =
        await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleConditionGet, queryParameters: postParams);
    List<VehicleConditionModel> vehicleConditions = List.generate(adsGenericModel.data.length, (index) => VehicleConditionModel.fromJson(adsGenericModel.data[index]));
    return vehicleConditions;
  }

  @override
  Future<List<VehicleCountryModel>> getVehicleCountries() async {
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleCountryGet,
    );
    List<VehicleCountryModel> vehicleConditions = List.generate(adsGenericModel.data.length, (index) => VehicleCountryModel.fromJson(adsGenericModel.data[index]));
    return vehicleConditions;
  }

  @override
  Future<List<VehicleMileageModel>> getVehicleMileages({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel =
        await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleMileageGet, queryParameters: postParams);
    List<VehicleMileageModel> vehicleMileages = List.generate(adsGenericModel.data.length, (index) => VehicleMileageModel.fromJson(adsGenericModel.data[index]));
    return vehicleMileages;
  }

  @override
  Future<List<VehicleYearModel>> getVehicleModelYears({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleModelYearGet,
      queryParameters: vehicleTypeId != -1 ? postParams : null,
    );
    List<VehicleYearModel> vehicleModelYears = List.generate(adsGenericModel.data.length, (index) => VehicleYearModel.fromJson(adsGenericModel.data[index]));
    return vehicleModelYears;
  }

  @override
  Future<List<VehicleModel>> getVehicleModels({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleModelGet,
      queryParameters: postParams,
    );
    List<VehicleModel> vehicleModels = List.generate(adsGenericModel.data.length, (index) => VehicleModel.fromJson(adsGenericModel.data[index]));
    return vehicleModels;
  }

  @override
  Future<List<VehicleBrandsModel>> getVehicleBrands({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleBrandGet,
      queryParameters: vehicleTypeId != -1 ? postParams : null,
    );
    List<VehicleBrandsModel> vehicleBrands = List.generate(adsGenericModel.data.length, (index) => VehicleBrandsModel.fromJson(adsGenericModel.data[index]));
    return vehicleBrands;
  }

  @override
  Future<List<VehicleSellerTypeModel>> getVehicleSellerTypes({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleSellerTypeGet,
      queryParameters: postParams,
    );
    List<VehicleSellerTypeModel> vehicleSellerTypes = List.generate(adsGenericModel.data.length, (index) => VehicleSellerTypeModel.fromJson(adsGenericModel.data[index]));
    return vehicleSellerTypes;
  }

  @override
  Future<List<VehicleTransmissionModel>> getVehicleTransmission({required int vehicleTypeId}) async {
    var postParams = {
      "VehicleType": vehicleTypeId.toString(),
    };
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleTransmissionGet,
      queryParameters: postParams,
    );
    List<VehicleTransmissionModel> vehicleTransmissions = List.generate(adsGenericModel.data.length, (index) => VehicleTransmissionModel.fromJson(adsGenericModel.data[index]));
    return vehicleTransmissions;
  }

  @override
  Future<VehicleDetailsModel> getVehicleDetails({int? vehicleTypeId, int? vehicleBrandId}) async {
    var postParams = {
      "vehicleType": vehicleTypeId == null ? 0 : vehicleTypeId.toString(),
      "isVehicleBrand": "true",
      "vehicleBrand": vehicleBrandId == null ? 0 : vehicleBrandId.toString(),
      "isVehicleCategory": "true",
      "isVehicleColor": "true",
      "isVehicleCondition": "true",
      "isVehicleMileage": "true",
      "isVehicleModel": "true",
      "isVehicleModelYear": "true",
      "isVehiclePriceRange": "true",
      "isVehiclePricingMethod": "true",
      "isVehcileSellerType": "true",
      "isVehicleTransmission": "true",
      "isCountry": "true"
    };

    String token = appState.getUser.data!.accessToken ?? "";
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleDetailsMaster,
      postParams,
      token: token,
    );
    VehicleDetailsModel vehicleDetails = VehicleDetailsModel.fromJson(adsGenericModel.data);
    return vehicleDetails;
  }

  @override
  Future<List<VehiclePartModel>> getVehicleDamageParts() async {
    GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
      token: appState.getUser.data!.accessToken,
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.vehicleDamagePartGet,
    );
    List<VehiclePartModel> vehicleParts = List.generate(adsGenericModel.data.length, (index) => VehiclePartModel.fromJson(adsGenericModel.data[index]));
    return vehicleParts;
  }

  @override
  Future<GenericRespModel> createComplainFromProvider({required int customerId, required String comment, required int complainType}) async {
    final providerId = appState.getUser.data!.userInfo!.providerId;
    final parameters = {
      "serviceProviderID": providerId,
      "customerID": customerId,
      "detail": comment,
      "complaintType": complainType,
    };
    GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
      (json) => GenericRespModel.fromJson(json),
      ApiConsts.providerComplaintCreate,
      parameters,
      token: appState.getUser.data!.accessToken,
    );
    return adsGenericModel;
  }
}
