package io.github.project_travel_mate.utilities;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;

import com.airbnb.lottie.LottieAnimationView;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.utils.Utils;

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

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

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnItemSelected;
import io.github.project_travel_mate.R;
import objects.ZoneName;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import utils.CurrencyConverterGlobal;
import utils.DateUtils;

import static utils.Constants.API_LINK_V2;
import static utils.Constants.USER_TOKEN;

public class CurrencyActivity extends AppCompatActivity {

    @BindView(R.id.animation_view)
    LottieAnimationView animationView;
    @BindView(R.id.actual_layout)
    View actual_layout;
    @BindView(R.id.first_country_image)
    ImageView from_image;
    @BindView(R.id.second_country_flag)
    ImageView to_image;
    @BindView(R.id.first_country_edittext)
    EditText from_edittext;
    @BindView(R.id.text_result)
    TextView result_textview;
    @BindView(R.id.first_country_name)
    TextView from_country_name;
    @BindView(R.id.second_country_name)
    TextView to_country_name;
    @BindView(R.id.graph)
    LineChart graph;
    @BindView(R.id.chart_duration_spinner)
    Spinner chart_duration_spinner;


    Boolean flag_check_first_item = false;
    Boolean flag_check_second_item = false;
    Boolean flag_convert_pressed = false;


    int from_amount = 1;
    String first_country_short = "USD";
    String second_country_short = "INR";
    String GRAPH_LABEL_NAME = "Last 7 days currency rate trends";

    private ProgressDialog mDialog;
    public static ArrayList<ZoneName> currences_names;

    public static String sDefSystemLanguage;
    private Context mContext;
    private Handler mHandler;
    private String mToken;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_utilities_currency_converter);
        ButterKnife.bind(this);
        setTitle(R.string.text_currency);

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        mToken = sharedPreferences.getString(USER_TOKEN, null);
        mDialog = new ProgressDialog(this);
        mDialog.setMessage(getResources().getString(R.string.progress_wait));
        mDialog.setTitle(R.string.app_name);
        mDialog.setCancelable(false);

        sDefSystemLanguage = Locale.getDefault().getLanguage();

        currences_names = new ArrayList<>();
        mHandler = new Handler(Looper.getMainLooper());
        mContext = this;

        Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
    }

    @OnClick(R.id.from_field)
    void fromSelected() {
        flag_check_first_item = true;
        flag_check_second_item = false;
        result_textview.setText(String.valueOf(0.0));
        Intent intent = new Intent(mContext, CurrencyListViewActivity.class);
        startActivity(intent);
    }

    @OnClick(R.id.to_field)
    void toSelected() {
        flag_check_second_item = true;
        flag_check_first_item = false;
        result_textview.setText(String.valueOf(0.0));
        Intent intent = new Intent(mContext, CurrencyListViewActivity.class);
        startActivity(intent);
    }

    @OnClick(R.id.button_convert)
    void onConvertclicked() {

        from_amount = Integer.parseInt(from_edittext.getText().toString());
        if (new Connection().isOnline()) {
            convertCurrency();
            int chartDays = getChartTimeInterval();
            currencyRate(chartDays);
            flag_convert_pressed = true;
            utils.Utils.hideKeyboard(this);
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(CurrencyActivity.this);
            builder.setTitle(R.string.app_name);
            builder.setMessage(R.string.check_internet);
            builder.setPositiveButton(R.string.positive_button, (dialog, which) -> dialog.dismiss());
            builder.show();
        }
    }

    @OnItemSelected(R.id.chart_duration_spinner)
    void onChartDurationSpinnerClicked() {
        // Flag is implemented here so that default behaviour of spinner's
        // on item selected doesn't trigger when activity is first launched
        if (flag_convert_pressed) {
            onConvertclicked();
            GRAPH_LABEL_NAME = "Last " + chart_duration_spinner.getSelectedItem() + " currency rate trends";
        }
    }


    // Method to obtain value(last x number of days) to be passed to API
    int getChartTimeInterval() {
        switch (chart_duration_spinner.getSelectedItemPosition()) {
            default:
                return 6;
            case 0:
                return 6;
            case 1:
                return 30;
            case 2:
                return 60;
            case 3:
                return 180;
            case 4:
                return 364;

        }
    }


    void setupGraph(JSONArray currencyRateTrends) {
        if (currencyRateTrends == null || currencyRateTrends.length() == 0) {
            graph.setVisibility(View.GONE);
            chart_duration_spinner.setVisibility(View.INVISIBLE);
        } else {
            graph.setVisibility(View.VISIBLE);
            chart_duration_spinner.setVisibility(View.VISIBLE);
            graph.getXAxis().setEnabled(false);
            graph.getAxisLeft().setEnabled(false);
            graph.getAxisRight().setEnabled(false);
            graph.getDescription().setText("");
            setGraphData(currencyRateTrends);
            graph.animateX(1000);
            Legend l = graph.getLegend();
            l.setForm(Legend.LegendForm.LINE);
        }
    }

    void setGraphData(JSONArray currencyRateTrends) {
        ArrayList<Entry> values = new ArrayList<>();

        for (int i = 0; i < currencyRateTrends.length(); i++) {
            try {
                values.add(new Entry(i, (float) currencyRateTrends.getDouble(i)));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        LineDataSet lineDataSet = new LineDataSet(values, GRAPH_LABEL_NAME);
        lineDataSet.setDrawIcons(false);
        lineDataSet.setColor(Color.RED);
        lineDataSet.setCircleColor(Color.BLUE);
        lineDataSet.setCircleRadius(1f);
        lineDataSet.setLineWidth(1f);
        lineDataSet.setCircleRadius(3f);
        lineDataSet.setDrawCircleHole(true);
        lineDataSet.setValueTextSize(10f);
        lineDataSet.setValueTextColor(Color.BLACK);
        lineDataSet.setDrawFilled(true);
        lineDataSet.setFormSize(10.f);
        if (Utils.getSDKInt() >= 18) {
            // fill drawable only supported on api level 18 and above
            Drawable drawable = ContextCompat.getDrawable(this, R.drawable.fade_green);
            lineDataSet.setFillDrawable(drawable);
        } else {
            lineDataSet.setFillColor(Color.BLACK);
        }

        ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
        dataSets.add(lineDataSet);

        // create a data object with the datasets
        LineData data = new LineData(dataSets);

        // set data
        graph.setData(data);

    }

    /**
     * Convert currency
     * and set result to result_textview
     */
    private void convertCurrency() {
        // to fetch weather forecast by city name
        String uri = API_LINK_V2 + "get-currency-conversion-rate/" + first_country_short + "/" + second_country_short;
        Log.v("EXECUTING", uri);

        mDialog.show();
        //Set up client
        OkHttpClient client = new OkHttpClient();
        //Execute request
        Request request = new Request.Builder()
                .header("Authorization", "Token " + mToken)
                .url(uri)
                .build();

        //Setup callback
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                mHandler.post(() -> {
                    mDialog.hide();
                    Log.e("Request Failed", "Message : " + e.getMessage());
                    cancelAnimation();
                    networkError();
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String jsonResponse = Objects.requireNonNull(response.body()).string();
                mHandler.post(() -> {
                    mDialog.hide();
                    if (response.isSuccessful()) {
                        try {
                            JSONObject result = new JSONObject(jsonResponse);
                            if (result.getString("result") != null) {
                                Double conversion = Double.parseDouble(result.getString("result"));
                                result_textview.setText(Double.toString(conversion * from_amount));
                            }
                            //cancel the loading animation once the data is fetched
                            cancelAnimation();

                        } catch (JSONException e) {
                            e.printStackTrace();
                            //display no data error animation
                            emptyListAnimation();
                        }
                    } else {
                        //display animation for no data returned from the API call
                        emptyListAnimation();
                    }
                });
            }
        });
    }

    /**
     * currency rate conversion
     * and set result to graph
     */
    private void currencyRate(int totalDays) {

        String uri = API_LINK_V2 + "get-all-currency-rate/"
                + DateUtils.getDate(totalDays) + "/" + DateUtils.getDate(0) + "/"
                + first_country_short.toLowerCase() + "/" + second_country_short.toLowerCase();

        mDialog.show();
        //Set up client

        OkHttpClient client = new OkHttpClient();
        //Execute request
        Request request = new Request.Builder()
                .header("Authorization", "Token " + mToken)
                .url(uri)
                .build();

        //Setup callback
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                mDialog.hide();
                mHandler.post(() -> {
                    cancelAnimation();
                    networkError();
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String jsonResponse = Objects.requireNonNull(response.body()).string();
                mHandler.post(() -> {
                    mDialog.hide();
                    if (response.isSuccessful()) {
                        try {
                            JSONArray result = new JSONArray(jsonResponse);
                            setupGraph(result);
                            //cancel the loading animation once the data is fetched
                            cancelAnimation();

                        } catch (JSONException e) {
                            e.printStackTrace();
                            //display no data error animation
                            emptyListAnimation();
                        }
                    } else {
                        //display animation for no data returned from the API call
                        emptyListAnimation();
                    }
                });
            }
        });


    }

    public static Intent getStartIntent(Context context) {
        return new Intent(context, CurrencyActivity.class);
    }

    @Override
    public void onResume() {
        super.onResume();
        if (flag_check_first_item) {
            if (CurrencyConverterGlobal.global_image_id != 0 &&
                    !CurrencyConverterGlobal.global_country_name.isEmpty()) {
                from_image.setImageResource(CurrencyConverterGlobal.global_image_id);
                from_country_name.setText(CurrencyConverterGlobal.global_country_name);
                first_country_short = CurrencyConverterGlobal.country_id;
                Log.d("Key", first_country_short);
            }
        }

        if (flag_check_second_item) {
            if (CurrencyConverterGlobal.global_image_id != 0 &&
                    !CurrencyConverterGlobal.global_country_name.isEmpty()) {
                to_image.setImageResource(CurrencyConverterGlobal.global_image_id);
                to_country_name.setText(CurrencyConverterGlobal.global_country_name);
                second_country_short = CurrencyConverterGlobal.country_id;
            }
        }
    }

    /**
     * Plays the network lost animation in the view
     */
    private void networkError() {
        animationView.setVisibility(View.VISIBLE);
        animationView.setAnimation(R.raw.network_lost);
        actual_layout.setVisibility(View.GONE);
        animationView.playAnimation();
    }

    /**
     * Plays the no data found animation in the view
     */
    private void emptyListAnimation() {
        animationView.setVisibility(View.VISIBLE);
        animationView.setAnimation(R.raw.empty_list);
        actual_layout.setVisibility(View.GONE);
        animationView.playAnimation();
    }

    /**
     * Cancel animation after receiving response from the API
     */
    private void cancelAnimation() {
        if (animationView != null) {
            animationView.cancelAnimation();
            animationView.setVisibility(View.GONE);
            actual_layout.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home)
            finish();
        return super.onOptionsItemSelected(item);
    }

    //    TODO : Move to different class
    class Connection {
        boolean isOnline() {
            ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo info = cm != null ? cm.getActiveNetworkInfo() : null;
            return info != null && info.isConnectedOrConnecting();
        }
    }

    /**
     * Error animation will be cancelled if user presses back while the animation is showing
     */
    @Override
    public void onBackPressed() {
        if (animationView != null) {
            if (animationView.getVisibility() == View.VISIBLE) {
                cancelAnimation();
                return;
            }
        }
        super.onBackPressed();
    }
}