package com.droideve.apps.dealify.fragments;

import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.droideve.apps.dealify.AppController;
import com.droideve.apps.dealify.R;
import com.droideve.apps.dealify.Services.GenericNotifyEvent;
import com.droideve.apps.dealify.activities.OrderDetailActivity;
import com.droideve.apps.dealify.activities.ProfileActivity;
import com.droideve.apps.dealify.adapter.Order.OrdersListExpandAdapter;
import com.droideve.apps.dealify.animation.LineItemDecoration;
import com.droideve.apps.dealify.appconfig.AppConfig;
import com.droideve.apps.dealify.appconfig.Constances;
import com.droideve.apps.dealify.classes.Category;
import com.droideve.apps.dealify.classes.Order;
import com.droideve.apps.dealify.classes.Setting;
import com.droideve.apps.dealify.classes.Store;
import com.droideve.apps.dealify.classes.User;
import com.droideve.apps.dealify.controllers.SettingsController;
import com.droideve.apps.dealify.controllers.categories.CategoryController;
import com.droideve.apps.dealify.controllers.orders.OrdersController;
import com.droideve.apps.dealify.controllers.sessions.SessionsController;
import com.droideve.apps.dealify.helper.CommunFunctions;
import com.droideve.apps.dealify.load_manager.ViewManager;
import com.droideve.apps.dealify.network.ServiceHandler;
import com.droideve.apps.dealify.network.VolleySingleton;
import com.droideve.apps.dealify.network.api_request.ApiRequest;
import com.droideve.apps.dealify.network.api_request.ApiRequestListeners;
import com.droideve.apps.dealify.network.api_request.SimpleRequest;
import com.droideve.apps.dealify.parser.Parser;
import com.droideve.apps.dealify.parser.api_parser.OrderParser;
import com.droideve.apps.dealify.parser.api_parser.StoreParser;
import com.droideve.apps.dealify.parser.tags.Tags;
import com.droideve.apps.dealify.restApi.OrderApis;
import com.droideve.apps.dealify.utils.NSLog;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.rey.material.widget.FloatingActionButton;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.realm.RealmList;

import static com.droideve.apps.dealify.appconfig.AppConfig.APP_DEBUG;


public class OrdersFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, ViewManager.CustomView, OrdersListExpandAdapter.OnItemClickListener, OrderApis.OrderRestAPisDelegate {


    @BindView(R.id.list)
    RecyclerView list;
    @BindView(R.id.refresh)
    SwipeRefreshLayout refresh;

    @BindView(R.id.fab)
    FloatingActionButton fab;


    private OrdersListExpandAdapter mAdapter;
    private RequestQueue queue;
    private ViewManager mViewManager;

    //pager
    private int COUNT = 0;
    private int REQUEST_PAGE = 1;
    private int pastVisiblesItems, visibleItemCount, totalItemCount;
    private LinearLayoutManager mLayoutManager;
    private boolean loading = true;
    private HashMap<String, String> listParams;
    private boolean expanded;
    private Store mStore;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_orders, container, false);
        ButterKnife.bind(this, rootView);


        if (getArguments() != null && !getArguments().isEmpty()) {
            if (getArguments().containsKey("params"))
                listParams = (HashMap<String, String>) getArguments().getSerializable("params");

            if (getArguments().containsKey("expanded"))
                expanded = getArguments().getBoolean("expanded");

        }

        initComponent();

        setupRefresListener();

        setupViewManager(rootView);

        switchToMaps();

        return rootView;

    }

    private void switchToMaps() {

        //fab.setVisibility(expanded ? View.VISIBLE : View.GONE);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                OrdersMapsFragment frag = new OrdersMapsFragment();
                FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
                transaction.replace(R.id.main_container, frag, "mapOrders");
                transaction.addToBackStack("mapOrders");

                transaction.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
                // Commit the transaction
                transaction.commit();
            }
        });


    }

    private void loadOrdersFromServer() {

        //load data from apis
        if (ServiceHandler.isNetworkAvailable(getContext())) {
            //open a specific order in the list
            getOrdersFromApi(REQUEST_PAGE, -1);
        } else {
            //get orders from local database
            List<Order> localOrders = OrdersController.findMyOrders(SessionsController.getSession().getUser().getId());
            mAdapter.addAllItems(localOrders);

            if (mAdapter.getItemCount() > 0) mViewManager.showResult();
            else mViewManager.empty();

            refresh.setRefreshing(false);
            Toast.makeText(getContext(), getString(R.string.check_network), Toast.LENGTH_LONG).show();

        }
    }


    private void setupViewManager(View view) {
        mViewManager = new ViewManager(getContext());
        mViewManager.setLoadingLayout(view.findViewById(R.id.loading));
        mViewManager.setResultLayout(view.findViewById(R.id.container));
        mViewManager.setErrorLayout(view.findViewById(R.id.error));
        mViewManager.setEmpty(view.findViewById(R.id.empty));
        mViewManager.setCustumizeView(this);
    }

    private void setupRefresListener() {
        refresh.setOnRefreshListener(this);
        refresh.setColorSchemeResources(
                R.color.colorAccent,
                R.color.colorAccent,
                R.color.colorAccent,
                R.color.colorAccent
        );
    }


    private void initComponent() {

        mLayoutManager = new LinearLayoutManager(getContext());
        list.setLayoutManager(mLayoutManager);
        list.addItemDecoration(new LineItemDecoration(getContext(), LinearLayout.VERTICAL));
        list.setHasFixedSize(true);

        //set data and list adapter
        mAdapter = new OrdersListExpandAdapter(getContext(), new ArrayList<>(), expanded);
        mAdapter.setOnItemClickListener(this);
        list.setAdapter(mAdapter);

        list.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

                visibleItemCount = mLayoutManager.getChildCount();
                totalItemCount = mLayoutManager.getItemCount();
                pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

                if (loading) {

                    if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                        loading = false;

                        if (ServiceHandler.isNetworkAvailable(getContext())) {
                            if (COUNT > mAdapter.getItemCount())
                                getOrdersFromApi(REQUEST_PAGE, -1);
                        } else {
                            Toast.makeText(getContext(), "Network not available ", Toast.LENGTH_SHORT).show();
                        }
                    }
                }
            }
        });


    }

    public List<Category> getData() {

        List<Category> results = new ArrayList<>();

        RealmList<Category> listCats = CategoryController.list();

        for (Category cat : listCats) {
            if (cat.getNumCat() > 0)
                results.add(cat);
        }


        return results;
    }


    // This method will be called when a Notification is posted (in the UI thread for Toast)
    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
    public void onMessageEvent(GenericNotifyEvent event) {
        //refresh notification list when the product is deleted
        if (event.message != null && event.message.equals("order_updated")) {
            loadOrdersFromServer();
            event.message = null;
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        loadOrdersFromServer();

    }


    @Override
    public void onPause() {
        super.onPause();
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return super.onOptionsItemSelected(item);
    }


    @Override
    public void onRefresh() {
        loadOrdersFromServer();
    }


    private boolean onLoad = false;
    private void getOrdersFromApi(final int page, final int order_id) {


        onLoad = true;
        refresh.setRefreshing(true);
        mViewManager.loading();


        Map<String, String> params = new HashMap<String, String>();

        if (order_id > 0)
            params.put("order_id", String.valueOf(order_id));

        params.put("page", String.valueOf(page));

        if (listParams != null && !listParams.isEmpty()) {
            for (Map.Entry<String, String> entry : listParams.entrySet()) {
                params.put(entry.getKey(), entry.getValue());
            }
        }

        //check excluded orders
        final SharedPreferences sharedPref = AppController.getInstance().getSharedPreferences("excluded_orders", Context.MODE_PRIVATE);
        String excluded_orders_ids = sharedPref.getString("ids", "");
        if (!excluded_orders_ids.equals(""))
            params.put("except", excluded_orders_ids);

        if (APP_DEBUG) {
            Log.e("ListOrdersFragment", "  params getOrders :" + params.toString());
        }
        ApiRequest.newPostInstance(Constances.API.API_ORDERS_GET, new ApiRequestListeners() {
            @Override
            public void onSuccess(Parser parser) {
                final OrderParser mParser = new OrderParser(parser);

                COUNT = mParser.getIntArg(Tags.COUNT);

                if (mParser.getSuccess() == 1) {
                    RealmList<Order> list = mParser.getOrders();
                    if (page == 1) mAdapter.removeAll();

                    for (int i = 0; i < list.size(); i++) {
                        mAdapter.addItem(list.get(i));
                    }
                    //save item into the database
                    OrdersController.insertOrders(list);
                    if (mAdapter.getItemCount() == 0) mViewManager.empty();
                    else mViewManager.showResult();

                    if (COUNT > mAdapter.getItemCount())
                        REQUEST_PAGE++;
                }

                onLoad = false;

                refresh.setRefreshing(false);
            }

            @Override
            public void onFail(Map<String, String> errors) {
                onLoad = false;
            }
        }, params);

    }



    @Override
    public void customErrorView(View v) {

        Button retry = v.findViewById(R.id.btn);

        retry.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getOrdersFromApi(REQUEST_PAGE, -1);
                REQUEST_PAGE = 1;
            }
        });

    }

    @Override
    public void customLoadingView(View v) {
    }

    @Override
    public void customEmptyView(View v) {

        if(listParams.containsKey("delivery_status")
                && Integer.parseInt(listParams.get("delivery_status"))==Constances.DELIVERY_STATUS.PENDING){

             ((TextView) v.findViewById(R.id.NO_RESULT)).setText(getString(R.string.no_order_found));
             ((TextView) v.findViewById(R.id.brief)).setText(getString(R.string.try_to_refresh_or_change_position));

             //setup timer
             new Timer().scheduleAtFixedRate(new TimerTask(){
                @Override
                public void run(){
                    reload();
                }
            },0,10000);
        }


        Button btn = v.findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mViewManager.loading();
                getOrdersFromApi(1, -1);
                REQUEST_PAGE = 1;
            }
        });


    }

    private void reload(){
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if(mAdapter.getItemCount() == 0 && !onLoad){
                    getOrdersFromApi(1, -1);
                    REQUEST_PAGE = 1;
                }
            }
        });
    }

    @Override
    public void onOrderDetailClick(int position) {
        Intent intent = new Intent(getActivity(), OrderDetailActivity.class);
        intent.putExtra("id", mAdapter.getItem(position).getId());
        startActivity(intent);
    }

    @Override
    public void onContactClick(int position) {


        //display bottom sheet dialog to contact both customer and shop owner
        showBottomSheetDialog(mAdapter.getItem(position));
    }


    public void getStoreDetail(final int store_id) {

        RequestQueue queue = VolleySingleton.getInstance(AppController.getInstance()).getRequestQueue();


        SimpleRequest request = new SimpleRequest(Request.Method.POST,
                Constances.API.API_USER_GET_STORES, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {

                try {

                    if (AppConfig.APP_DEBUG) {
                        Log.e("responseStoresString", response);
                    }

                    JSONObject jsonObject = new JSONObject(response);
                    final StoreParser mStoreParser = new StoreParser(jsonObject);
                    RealmList<Store> list = mStoreParser.getStore();

                    if (list.size() > 0) {
                        mStore = list.get(0);
                    }

                } catch (JSONException e) {
                    //send a rapport to support
                    e.printStackTrace();

                }


            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (AppConfig.APP_DEBUG) {
                    Log.e("ERROR", error.toString());
                }
            }
        }) {

            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<String, String>();

                params.put("limit", "1");
                params.put("store_id", String.valueOf(store_id));


                return params;
            }

        };


        request.setRetryPolicy(new DefaultRetryPolicy(SimpleRequest.TIME_OUT,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

        queue.add(request);


    }

    private void showBottomSheetDialog(final Order order) {

        FrameLayout bottom_sheet = getView().findViewById(R.id.bottom_sheet);
        bottom_sheet.setVisibility(View.VISIBLE);

        final BottomSheetBehavior[] mBehavior = {BottomSheetBehavior.from(bottom_sheet)};
        final BottomSheetDialog[] mBottomSheetDialog = {new BottomSheetDialog(getContext())};

        if (mBehavior[0].getState() == BottomSheetBehavior.STATE_EXPANDED) {
            mBehavior[0].setState(BottomSheetBehavior.STATE_COLLAPSED);
        }

        final View[] view = {getLayoutInflater().inflate(R.layout.order_location_sheet, null)};


        //action qte buttons
        (view[0].findViewById(R.id.btn_call_client)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String phoneNumber = null;
                String req_cf_data = order.getReq_cf_data();
                if (req_cf_data != null && !req_cf_data.equals("null")) {
                    try {
                        JSONObject cfObj = new JSONObject(req_cf_data);
                        if (cfObj.has("Phone"))
                            phoneNumber = cfObj.getString("Phone");

                        Intent intent = new Intent(Intent.ACTION_DIAL);
                        intent.setData(Uri.parse("tel:" + phoneNumber.trim()));
                        if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {

                            String[] permission = new String[]{Manifest.permission.CALL_PHONE};
                            SettingsController.requestPermissionM(getActivity(), permission);
                            return;
                        }
                        startActivity(intent);

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                mBottomSheetDialog[0].dismiss();
            }
        });

        (view[0].findViewById(R.id.btn_call_owner)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                refresh.setRefreshing(true);
                //get store from order obj
                getStoreDetail(order.getId_store());

                //show ad
                (new Handler()).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (mStore != null) {
                            Intent intent = new Intent(Intent.ACTION_DIAL);
                            intent.setData(Uri.parse("tel:" + mStore.getPhone()));
                            if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                                String[] permission = new String[]{Manifest.permission.CALL_PHONE};
                                SettingsController.requestPermissionM(getActivity(), permission);
                                return;
                            }
                            startActivity(intent);
                            mBottomSheetDialog[0].dismiss();
                            refresh.setRefreshing(false);
                        }
                    }
                }, 2000);


            }
        });

        mBottomSheetDialog[0].setContentView(view[0]);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mBottomSheetDialog[0].getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }

        mBottomSheetDialog[0].show();
        mBottomSheetDialog[0].setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                mBottomSheetDialog[0] = null;
            }
        });
    }


    @Override
    public void onUpdateStatusClick(int position) {

        //check if the user is confirmed first
        if (SessionsController.getSession().getUser().getConfirmed() == 0) {
            Map<String, String> errors = new HashMap<String, String>();
            errors.put("AccountNotConfirmed:", getString(R.string.account_need_to_be_confirmed));
            CommunFunctions.showErrors("Locked account", errors, getContext());
            return;
        }

        Setting defaultAppSetting = SettingsController.findSettingFiled("USER_PHONE_VERIFICATION");
        User currentUser = SessionsController.getSession().getUser();
        if (defaultAppSetting != null && defaultAppSetting.getValue().equals("1") && currentUser.getPhone_verified() == 0) {
            /*if (currentUser.getPhone() != null && !currentUser.getPhone().equalsIgnoreCase(""))
                startActivity(new Intent(getActivity(), otp.class));
            else
                startActivity(new Intent(getActivity(), ProfileActivity.class));
            return;*/
        }


        String[] list_status = new String[]{getString(R.string.accept), getString(R.string.decline)};

        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setTitle(R.string.update_order_status);
        builder.setSingleChoiceItems(list_status, 0, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                //Toast.makeText(getActivity(), "Order updated to : " + list_status[i], Toast.LENGTH_SHORT).show();
                // selectedOption[0] = (i == 0) ? 1 : 0;
            }
        });
        builder.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                //todo : confirm order status
                int selectedPosition = ((AlertDialog) dialogInterface).getListView().getCheckedItemPosition();
                if (selectedPosition == 0) { // order is accepted
                    HashMap<String, String> listParams = new HashMap<>();

                    listParams.put("delivery_id", String.valueOf(SessionsController.getSession().getUser().getId()));
                    listParams.put("order_id", String.valueOf(mAdapter.getItem(position).getId()));
                    listParams.put("message", "");
                    listParams.put("status", String.valueOf(Constances.DELIVERY_STATUS.ONGOING));

                    (new Handler()).postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            refresh.setRefreshing(true);
                            //call apis to update the offers
                            OrderApis call = OrderApis.newInstance();
                            call.delegate = OrdersFragment.this;
                            call.updateOrderStatus(listParams);
                        }
                    }, 2500);


                } else if (selectedPosition == 1) { // order is declined
                    refresh.setRefreshing(true);

                    //save order id in excluded list in shared pred
                    final SharedPreferences sharedPref = AppController.getInstance().getSharedPreferences("excluded_orders", Context.MODE_PRIVATE);
                    String excluded_orders_ids = sharedPref.getString("ids", "");
                    excluded_orders_ids += mAdapter.getItem(position).getId() + ";";
                    sharedPref.edit().putString("ids", excluded_orders_ids).apply();

                    //refresh the orders list
                    loadOrdersFromServer();

                }


            }
        });
        builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

            }

        });
        builder.show();

    }


    @Override
    public void onStoreSuccess(Store storeData) {

    }

    @Override
    public void onCustomerSuccess(User userData) {

    }

    @Override
    public void onOrderUpdate(JSONObject jsonObject) {

        if (jsonObject != null) {
            try {

                //refresh the orders list
                loadOrdersFromServer();

                Intent intent = new Intent(getActivity(), OrderDetailActivity.class);
                intent.putExtra("id", jsonObject.getInt("result"));
                startActivity(intent);


            } catch (JSONException e) {
                e.printStackTrace();
                refresh.setRefreshing(false);
            }

        }
    }

    @Override
    public void onError(OrderApis object, Map<String, String> errors) {

    }
}
