package com.withpersona.sdk2.reactnative;

import static com.withpersona.sdk2.reactnative.InquiryUtils.collectedDataToMap;
import static com.withpersona.sdk2.reactnative.InquiryUtils.wrapField;

import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.withpersona.sdk2.inquiry.InquiryField;
import com.withpersona.sdk2.inquiry.InquiryResponse;

import java.util.Map;

public class InquiryResultEmitter {
    @NonNull private final ReactContext reactContext;

    public InquiryResultEmitter(@NonNull ReactContext reactContext) {
        this.reactContext = reactContext;
    }

    @Nullable
    private WritableMap responseToMap(@Nullable InquiryResponse response) {
        if (response instanceof InquiryResponse.Complete) {
            InquiryResponse.Complete complete = ((InquiryResponse.Complete) response);

            // Build event params
            WritableMap params = Arguments.createMap();
            params.putString("inquiryId", complete.getInquiryId());
            params.putString("status", complete.getStatus());

            WritableMap fields = Arguments.createMap();
            Map<String, InquiryField> rawFields = complete.getFields();
            for (String fieldName : rawFields.keySet()) {
                InquiryField rawField = rawFields.get(fieldName);
                if (rawField instanceof InquiryField.StringField) {
                    fields.putMap(fieldName,
                            wrapField("string", ((InquiryField.StringField) rawField).getValue()));
                } else if (rawField instanceof InquiryField.IntegerField) {
                    Integer value = ((InquiryField.IntegerField) rawField).getValue();
                    fields.putMap(fieldName,
                            wrapField("integer", (value == null) ? null : value.toString()));
                } else if (rawField instanceof InquiryField.BooleanField) {
                    Boolean value = ((InquiryField.BooleanField) rawField).getValue();
                    fields.putMap(fieldName,
                            wrapField("boolean", (value == null) ? null : value.toString()));
                } else if (rawField instanceof InquiryField.UnknownField) {
                    String type = ((InquiryField.UnknownField) rawField).getType();
                    fields.putMap(fieldName, wrapField("unknown", type));
                } else {
                    fields.putMap(fieldName, wrapField("unknown", null));
                }
            }
            params.putMap("fields", fields);

            params.putMap("collectedData", collectedDataToMap(complete.getCollectedData()));

            return params;
        } else if (response instanceof InquiryResponse.Cancel) {
            InquiryResponse.Cancel cancel = (InquiryResponse.Cancel) response;

            // Build event params
            WritableMap params = Arguments.createMap();
            params.putString("inquiryId", cancel.getInquiryId());
            params.putString("sessionToken", cancel.getSessionToken());

            return params;
        } else if (response instanceof InquiryResponse.Error) {
            InquiryResponse.Error error = (InquiryResponse.Error) response;

            WritableMap params = Arguments.createMap();
            params.putString("debugMessage", error.getDebugMessage());
            params.putString("errorCode", error.getErrorCode().name());

            return params;
        }
        return null;
    }

    public void emitResponse(@Nullable InquiryResponse response, @NonNull View view) {
        RCTEventEmitter emitter = reactContext.getJSModule(RCTEventEmitter.class);

        if (response instanceof InquiryResponse.Complete) {
            emitter.receiveEvent(view.getId(), "onComplete", responseToMap(response));
        } else if (response instanceof InquiryResponse.Cancel) {
            emitter.receiveEvent(view.getId(), "onCanceled", responseToMap(response));
        } else if (response instanceof InquiryResponse.Error) {
            emitter.receiveEvent(view.getId(), "onError", responseToMap(response));
        }
    }

    public void emitResponse(@Nullable InquiryResponse response) {
        DeviceEventManagerModule.RCTDeviceEventEmitter jsModule =
                this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);

        if (response instanceof InquiryResponse.Complete) {
            jsModule.emit("onComplete", responseToMap(response));
        } else if (response instanceof InquiryResponse.Cancel) {
            jsModule.emit("onCanceled", responseToMap(response));
        } else if (response instanceof InquiryResponse.Error) {
            jsModule.emit("onError", responseToMap(response));
        }
    }
}
