package com.app.simplitend.welcome.welcomepatient.mvvm;

import static com.app.simplitend.apputils.RetrofitHelper.getRetrofit;

import android.util.Log;

import androidx.annotation.NonNull;

import com.app.simplitend.welcome.welcomepatient.mvvm.models.CallResponse;
import com.app.simplitend.welcome.welcomepatient.mvvm.models.OTPSentResponse;
import com.app.simplitend.welcome.welcomepatient.mvvm.models.PatientData;

import java.util.List;
import java.util.Map;

import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class WelcomeRepository {

    private static final String TAG = "WelcomeRepository";

    private static WelcomeRepository welcomeRepository;

    private final WelcomeApiService welcomeApiService;

    private WelcomeRepository() {
        welcomeApiService = getRetrofit().create(WelcomeApiService.class);
    }

    public static synchronized WelcomeRepository getWelcomeRepository(){
        if (welcomeRepository == null){
            welcomeRepository = new WelcomeRepository();
        }

        return welcomeRepository;
    }

    public void loginPatient(@NonNull Map<String, RequestBody> credentials,
                             @NonNull WelcomeContracts.RegisterPatientContract loginCallback){

        welcomeApiService.loginPatient(credentials).enqueue(new Callback<CallResponse<PatientData>>() {
            @Override
            public void onResponse(Call<CallResponse<PatientData>> call, Response<CallResponse<PatientData>> response) {
                if (response.body() != null){
                    if (response.body().status != 200 || response.body().result == null){
                        loginCallback.onFailure(new Exception(), response.body().message, response.body().status);
                        return;
                    }

                    loginCallback.onResponse(response.body().result, response.body().token);
                }else{
                    loginCallback.onFailure(new Exception(), "Please try again later.", response.code());
                }
            }

            @Override
            public void onFailure(Call<CallResponse<PatientData>> call, Throwable t) {
                Log.e(TAG, "onFailure: login patient", t);
                loginCallback.onFailure(t, t.getMessage(), 1);
            }
        });

    }

    public void registerPatient(@NonNull Map<String, RequestBody> body,
                                @NonNull WelcomeContracts.RegisterPatientContract registerPatient){



        welcomeApiService.registerPatient(body).enqueue(new Callback<CallResponse<PatientData>>() {
            @Override
            public void onResponse(Call<CallResponse<PatientData>> call, Response<CallResponse<PatientData>> response) {
                if (response.isSuccessful() && response.body() != null && response.body().result != null)
                {
                    registerPatient.onResponse(response.body().result, response.body().token);
                }else if (response.body() != null){
                    Log.e(TAG, "onResponse: " + response);
                    registerPatient.onFailure(new Exception(response.toString()), response.body().message, response.code());
                }else{
                    Log.e(TAG, "onResponse: no success response and also response body is null");
                    registerPatient.onFailure(new Exception("no success response and also response body is null"), "It's not you, it's us.\nPlease try again later", 1);
                }
            }

            @Override
            public void onFailure(Call<CallResponse<PatientData>> call, Throwable t) {
                Log.e(TAG, "onFailure: ", t);
                registerPatient.onFailure(t, t.getMessage(), 1);
            }
        });

    }

    public void verifyEmail(Map<String, String> email_address, WelcomeContracts.VerifyEmailCallBack emailCallBack){

        welcomeApiService.verifyEmail(email_address).enqueue(new Callback<CallResponse<PatientData>>() {
            @Override
            public void onResponse(Call<CallResponse<PatientData>> call, Response<CallResponse<PatientData>> response) {
                Log.d(TAG, "onResponse: ");
                if (response.isSuccessful() && response.body() != null){
                    // error_cede
                    // 0 -> email is not exist in database
                    // 1 -> email is present in database
                    emailCallBack.onEmailVerified(response.body().error_code == 1, response.body().message);
                }else{
                    emailCallBack.onVerificationFailed();
                }
            }

            @Override
            public void onFailure(Call<CallResponse<PatientData>> call, Throwable t) {
                Log.e(TAG, "onFailure: verify email ", t);
                emailCallBack.onVerificationFailed();
            }
        });

    }

    public void sendOTPToEmail(String email_address,
                               @NonNull WelcomeContracts.SendOTPToEmailCallback otpToEmailCallback){

        welcomeApiService.sendOTPToEmail(email_address)
                .enqueue(new Callback<CallResponse<OTPSentResponse>>() {
                    @Override
                    public void onResponse(Call<CallResponse<OTPSentResponse>> call, Response<CallResponse<OTPSentResponse>> response) {
                        if (response.body() != null){
                            if (response.body().status != 200 || response.body().result == null){
                                otpToEmailCallback.onOTPSentFailed(new Exception(), response.body().message);
                                return;
                            }

                            otpToEmailCallback.onOTPSent(response.body().result);
                        }else{
                            otpToEmailCallback.onOTPSentFailed(new Exception(), "Please try again later.");
                        }
                    }

                    @Override
                    public void onFailure(Call<CallResponse<OTPSentResponse>> call, Throwable t) {
                        otpToEmailCallback.onOTPSentFailed(t, "Please try again later.");
                        Log.e(TAG, "onFailure: ", t);
                    }
                });
    }

    public void verifyOTP(Map<String, RequestBody> body,
                          @NonNull WelcomeContracts.VerifyOTPCallback verifyOTPCallback){
        welcomeApiService.verifyOTP(body).enqueue(new Callback<CallResponse<List<String>>>() {
            @Override
            public void onResponse(Call<CallResponse<List<String>>> call, Response<CallResponse<List<String>>> response) {
                if (response.body() != null){
                    if (response.body().status != 200 || response.body().result == null){
                        verifyOTPCallback.onOTPVerificationFailed(new Exception(), response.body().message);
                        return;
                    }

                    verifyOTPCallback.onOTPVerified();
                }else{
                    verifyOTPCallback.onOTPVerificationFailed(new Exception(), "Please try again later.");
                }
            }

            @Override
            public void onFailure(Call<CallResponse<List<String>>> call, Throwable t) {
                verifyOTPCallback.onOTPVerificationFailed(t, "Please try again later.");
                Log.e(TAG, "onFailure: ", t);
            }
        });
    }

    public void updatePin(Map<String, RequestBody> body,
                          @NonNull WelcomeContracts.UpdatePinCallback updatePinCallback){

        welcomeApiService.updatePin(body)
                .enqueue(new Callback<CallResponse<PatientData>>() {
                    @Override
                    public void onResponse(Call<CallResponse<PatientData>> call, Response<CallResponse<PatientData>> response) {
                        if (response.body() != null){
                            if (response.body().status != 200 || response.body().result == null){
                                updatePinCallback.onPinUpdateFailed(new Exception(), response.body().message);
                                return;
                            }

                            updatePinCallback.onPinUpdated(response.body().result);
                        }else{
                            updatePinCallback.onPinUpdateFailed(new Exception(), "Please try again later.");
                        }
                    }

                    @Override
                    public void onFailure(Call<CallResponse<PatientData>> call, Throwable t) {
                        updatePinCallback.onPinUpdateFailed(t, "Please try again later.");
                        Log.e(TAG, "onFailure: ", t);
                    }
                });
    }

}
