package demo.mapi.ccv.eu.mapi_demo.activities.attended;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import com.google.gson.Gson;

import org.apache.commons.lang.StringUtils;

import demo.mapi.ccv.eu.mapi_demo.AndroidLogger;
import demo.mapi.ccv.eu.mapi_demo.MapiDemoState;
import demo.mapi.ccv.eu.mapi_demo.R;
import eu.ccvlab.mapi.core.logging.MPALogging;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import demo.mapi.ccv.eu.mapi_demo.AndroidLogger;
import demo.mapi.ccv.eu.mapi_demo.MapiDemoState;
import demo.mapi.ccv.eu.mapi_demo.R;
import eu.ccvlab.mapi.core.logging.MPALogging;

public class AttendedSettingsActivity extends AppCompatActivity {
    public Spinner socketModeSpinner;
    public Spinner opiDialectSpinner;
    public EditText port;
    public View portLayout;
    public EditText compatibilityPort;
    public EditText hostname;
    public EditText receiptNumber;
    public EditText referenceNumber;
    public EditText transactionId;
    public EditText myCCVShopLocationId;

    private MapiDemoState appState = new MapiDemoState();

    @SuppressWarnings("PMD.AvoidPrintStackTrace")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.attended_settings_activity);
        socketModeSpinner = findViewById(R.id.socketMode);
        opiDialectSpinner = findViewById(R.id.dialects);
        portLayout = findViewById(R.id.portLayout);
        compatibilityPort = findViewById(R.id.compatibilityPort);
        hostname = findViewById(R.id.hostname);
        receiptNumber = findViewById(R.id.receiptNumber);
        referenceNumber = findViewById(R.id.referenceNumber);
        transactionId = findViewById(R.id.transactionId);
        port = findViewById(R.id.port);
        myCCVShopLocationId = findViewById(R.id.myCCVShopLocationIdInput);
        findViewById(R.id.terminal_save_button).setOnClickListener((View view) -> onClickSave());

        MPALogging.addLogger(new AndroidLogger("AttendedSettingsActivity"));
        loadLastAppState();
        initWidgets();
    }

    public void onClickSave() {
        saveNewAppState();
        onBackPressed();
    }

    private void initWidgets() {
        socketModeSpinner = initSocketModeButton();
        opiDialectSpinner = initOpiDialectSpinner();
        refreshDisplayedSettings();
    }

    @NonNull
    private ArrayAdapter<CharSequence> createSpinnerAdapter(AttendedSettingsActivity context, int flows_array) {
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context,
                flows_array, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        return adapter;
    }

    private Spinner initOpiDialectSpinner() {
        final ArrayAdapter<CharSequence> adapter = createSpinnerAdapter(this, R.array.dialects_array);
        opiDialectSpinner.setAdapter(adapter);
        opiDialectSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
                String opiDialect = (String) adapterView.getItemAtPosition(position);
                appState.selectedOpiProtocol(opiDialect);
                refreshDisplayedSettings();
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
            }
        });

        return opiDialectSpinner;
    }

    private Spinner initSocketModeButton() {
        final ArrayAdapter<CharSequence> adapter = createSpinnerAdapter(this, R.array.socket_modes);
        socketModeSpinner.setAdapter(adapter);
        socketModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
                boolean isChecked = (position == 1);
                portLayout.getLayoutParams().width = isChecked ? Toolbar.LayoutParams.WRAP_CONTENT : Toolbar.LayoutParams.MATCH_PARENT;
                compatibilityPort.setVisibility(isChecked ? View.VISIBLE : View.GONE);
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
            }
        });
        return socketModeSpinner;
    }

    @SuppressLint("LongLogTag")
    private void loadLastAppState() {
        String xml = null;
        try {
            File file = getApplicationContext().getFileStreamPath("state.json");

            int size = (int) file.length();
            byte[] bytes = new byte[size];
            BufferedInputStream buf;

            buf = new BufferedInputStream(new FileInputStream(file));
            buf.read(bytes, 0, bytes.length);
            buf.close();

            xml = new String(bytes);
        } catch (IOException e) {
            Log.e("AttendedTerminalActivity", "Unable to read previous app state");
        }

        this.appState = xml != null ? new Gson().fromJson(xml, MapiDemoState.class) : new MapiDemoState();
    }

    private boolean isSingleSocketSelected() {
        return socketModeSpinner.getSelectedItemId() == 0;
    }

    @SuppressLint("LongLogTag")
    private void saveNewAppState() {
        try {
            String protocol = opiDialectSpinner.getSelectedItem().toString();
            appState.setPort(protocol, port.getText().toString());
            appState.setCompatibilityPort(protocol, compatibilityPort.getText().toString());
            appState.setHostname(protocol, hostname.getText().toString());
            appState.setTransactionId(protocol, transactionId.getText().toString());
            appState.setReceiptNumber(protocol, receiptNumber.getText().toString());
            String reference = referenceNumber.getText().toString();
            appState.setReferenceNumber(protocol, StringUtils.isNotEmpty(reference) ? Integer.parseInt(reference) : null);
            appState.setSingleSocket(protocol, isSingleSocketSelected());
            appState.selectedOpiProtocol(protocol);
            appState.setMyCCVShopLocationId(protocol, myCCVShopLocationId.getText().toString());
            Gson gson = new Gson();
            String json = gson.toJson(this.appState);
            FileOutputStream fileOutputStream = getApplicationContext().openFileOutput("state.json", Context.MODE_PRIVATE);
            fileOutputStream.write(json.getBytes());
            fileOutputStream.close();
        } catch (IOException e) {
            Log.e("UnAttendedSettingsActivity", "Failed to save app state: " + e.getLocalizedMessage());
        }
    }

    private void refreshDisplayedSettings() {
        String protocol = appState.selectedOpiProtocol();
        port.setText(appState.getPort(protocol));
        compatibilityPort.setText(appState.getCompatibilityPort(protocol));
        transactionId.setText(appState.getTransactionId(protocol));
        receiptNumber.setText(appState.getReceiptNumber(protocol));
        hostname.setText(appState.getHostname(protocol));
        socketModeSpinner.setSelection(appState.isSingleSocket(protocol) ? 0 : 1);
        opiDialectSpinner.setSelection(returnOpiDialectPosition());
        myCCVShopLocationId.setText(appState.getMyCCVShopLocationId(protocol));
    }

    private int returnOpiDialectPosition() {
        switch (appState.selectedOpiProtocol()) {
            case "OPI-CH":
                return 1;
            case "OPI-DE":
                return 2;
            case "OPI-NL":
            default:
                return 0;
        }
    }
}
