/*
 * Copyright 2017 .
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.dinect.checker;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.dinect.checker.net.ApiClient;

import org.json.JSONArray;
import org.json.JSONException;

import java.io.IOException;
import java.util.Locale;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import okhttp3.ResponseBody;


/**
 * Created by anonymous
 */

public abstract class AbstractScannerActivity extends AppCompatActivity {

    private final static String TAG = "Checker.ScannerActivity";

    private int counter;

    public static final String SCAN_MODES = "SCAN_MODES";
    public static final String ERROR_INFO = "ERROR_INFO";

    protected LogoutDialogFragment logoutDialog;
    private ApiClient mClient;

    boolean isCameraAvailable() {
        Log.d(TAG, "isCameraAvailable");
        PackageManager pm = getPackageManager();
        return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
    }

    void cancelRequest(final @NonNull String message) {
        Log.d(TAG, "cancelRequest: " + message);
        final Intent response = new Intent();
        response.putExtra(ERROR_INFO, message);
        setResult(RESULT_CANCELED, response);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final String appToken = getIntent().getStringExtra(MainActivity.PREF_APP_TOKEN);
        final String token = getIntent().getStringExtra(MainActivity.PREF_POS_TOKEN);
        final String url = getIntent().getStringExtra(MainActivity.PREF_API_URL) + "/users/";
        mClient = new ApiClient(url, appToken, token);
    }

    /**
     * initialize activity
     * - removes windows title
     * - set content view to layout id
     *
     * @param layoutID layout to use
     */
    protected final boolean init(final int layoutID) {
        Log.d(TAG, "init");
        if (!isCameraAvailable()) {
            // Cancel request if there is no rear-facing camera.
            cancelRequest("Camera unavailable");
            return false;
        }
        // Hide the window title.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(layoutID);
        return true;
    }

    /**
     * Configure toolbar of app
     */
    protected final void initToolbar(Intent intent) {

        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setBackgroundColor((int) intent.getLongExtra(MainActivity.PREF_APP_BAR_COLOR, 0xffffff));
        setSupportActionBar(toolbar);

        final ActionBar actionBar = getSupportActionBar();

        if (actionBar != null) {
            actionBar.setTitle(null);
            actionBar.setDisplayHomeAsUpEnabled(false);
        }

        initManualInput();
        setupSecretClickHandler(toolbar);
    }

    private void initManualInput() {
        EditText manualInput = (EditText) findViewById(R.id.manual_input);


        manualInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                handleBarcode(v.getText().toString());
                return false;
            }
        });

    }

    private void setupSecretClickHandler(final @NonNull View toolbar) {
        // Configure increment handler
        toolbar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (counter == 15) {
                    switchScanner();
                } else {
                    counter++;
                }
                Log.d(TAG, "toolbar clicked " + counter + " times");
            }
        });
    }

    private void switchScanner() {

        final SharedPreferences prefs = getSharedPreferences("scanner", Context.MODE_PRIVATE);

        int idx = (prefs.getInt(MainActivity.SCANNER_BACKEND_KEY, 0) == MainActivity.ZXING)
                ? MainActivity.ZBAR
                : MainActivity.ZXING;

        Log.d(TAG, "switch to scanner backend " + idx + ", " + MainActivity.SCANNER_BACKEND[idx].toString());
        prefs.edit().putInt(MainActivity.SCANNER_BACKEND_KEY, idx).apply();

        cancelRequest("Scanner backend changed");
        setResult(RESULT_OK);
        finish();
    }


    /**
     * Adds scanner view to target frame layout
     */
    protected final void addScanner(final @NonNull View view, final int targetFrameId) {
        Log.d(TAG, "addScanner");
        final FrameLayout root = (FrameLayout) findViewById(targetFrameId);
        root.addView(view, 0);
    }

    protected abstract View initScanner();

    public void handleBarcode(final @NonNull String card) {
        mClient.findUser(card, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleFail(card);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    ResponseBody body = response.body();
                    if (body != null) {
                        switch (response.code()) {
                            case 200:
                                final JSONArray users = new JSONArray(body.string());
                                if (users.length() > 0) {
                                    handleSuccess(card, users.get(0).toString());
                                } else {
                                    handleFail(card);
                                }
                                break;
                            case 204:
                                handleFail(card);
                                break;
                        }
                    }
                } catch (final IOException | JSONException e) {
                    Log.e(TAG, e.getMessage(), e);
                    handleFail(card);
                }
            }
        });
    }

    protected final void handleSuccess(final String card, final String user) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                setResult(RESULT_OK, new Intent().putExtra("user", user).putExtra("card", card));
                finish();
            }
        });
    }

    protected final void handleFail(final String card) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                String message = String.format(getString(R.string.identifier_not_found), card)
                        + ".\n"
                        + String.format(getString(R.string.error_contact_support), BuildConfig.supportPhone);
                Toast.makeText(AbstractScannerActivity.this, message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.findItem(R.id.settings).setIcon(getResources().getDrawable(R.drawable.settings));
        menu.findItem(R.id.faq).setIcon(getResources().getDrawable(R.drawable.help));
        menu.findItem(R.id.logout).setIcon(getResources().getDrawable(R.drawable.logout));
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.settings) {
            final Intent intent = new Intent();
            intent.putExtra("item", "settings");
            setResult(RESULT_OK, intent);
            finish();
            return true;
        } else if (item.getItemId() == R.id.logout) {
            int color = (int) getIntent().getLongExtra(MainActivity.PREF_APP_BAR_COLOR, 0xffffff);
            logoutDialog = LogoutDialogFragment.newInstance(color);
            logoutDialog.show(getFragmentManager(), "logout");
            return true;
        } else if (item.getItemId() == R.id.faq) {
            final Intent intent = new Intent();
            intent.putExtra("item", "faq");
            setResult(RESULT_OK, intent);
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    void dismissDialog() {
        if (logoutDialog != null) {
            logoutDialog.dismiss();
            logoutDialog = null;
        }
    }

    void logout() {
        final Intent intent = new Intent();
        intent.putExtra("item", "logout");
        setResult(RESULT_OK, intent);
        finish();
    }

    public static class LogoutDialogFragment extends DialogFragment {

        static LogoutDialogFragment newInstance(int color) {
            LogoutDialogFragment f = new LogoutDialogFragment();
            Bundle bundle = new Bundle();
            bundle.putInt(MainActivity.PREF_APP_BAR_COLOR, color);
            f.setArguments(bundle);
            return f;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            final LayoutInflater inflater = getActivity().getLayoutInflater();
            final View content = inflater.inflate(R.layout.f_logout_dialog, null);
            builder.setView(content);
            final TextView positiveButton = (TextView) content.findViewById(R.id.positiveButton);
            final TextView negativeButton = (TextView) content.findViewById(R.id.negativeButton);
            // Можно делать через стили, но я не уверен, что необходимо в нашем случае
            positiveButton.setTextColor(getArguments().getInt(MainActivity.PREF_APP_BAR_COLOR));
            negativeButton.setTextColor(getArguments().getInt(MainActivity.PREF_APP_BAR_COLOR));

            negativeButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ((AbstractScannerActivity) getActivity()).dismissDialog();
                }
            });

            positiveButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ((AbstractScannerActivity) getActivity()).logout();
                }
            });

            return builder.create();
        }
    }
}
