/**
 * MIT License
 *
 * Copyright (c) 2016 Hishmad Abubakar Al-Amudi
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.stockita.stockitapointofsales.itemmaster;

import android.app.DialogFragment;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;

import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.stockita.stockitapointofsales.R;
import com.stockita.stockitapointofsales.customViews.AdapterViewItemLookup;
import com.stockita.stockitapointofsales.data.ItemImageModel;
import com.stockita.stockitapointofsales.data.ItemModel;
import com.stockita.stockitapointofsales.interfaces.OpenSalesHeaderListCallbacks;
import com.stockita.stockitapointofsales.interfaces.SalesDetailPendingCallbacks;
import com.stockita.stockitapointofsales.utilities.Constants;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import butterknife.Bind;
import butterknife.ButterKnife;

/**
 * This class will show a dialog fragment to lookup into a list of item master
 * so the user can click one of them to be added into the sales dialog
 */
public class LookupItemMasterListDialogFragment extends DialogFragment {

    // Constant
    private static final String TAG_LOG = LookupItemMasterListDialogFragment.class.getSimpleName();
    private static final String KEY_DATA_USER_UID = TAG_LOG +  ".KEY_DATA_USER_UID";
    private static final String KEY_DATA_REQUEST_CODE = TAG_LOG + ".KEY_DATA_REQUEST_CODE";
    private static final String KEY_DATA_ITEM_MASTER_KEY_LIST = TAG_LOG + ".KEY_DATA_ITEM_MASTER_KEY_LIST";
    private static final String KEY_DATA_SALES_HEADER_KEY = TAG_LOG + ".KEY_DATA_SALES_HEADER_KEY";
    private static final String KEY_ONE = TAG_LOG + ".KEY_ONE";
    private static final String KEY_TWO = TAG_LOG + ".KEY_TWO";
    private static final String KEY_THREE = TAG_LOG + ".KEY_THREE";
    private static final String KEY_FOUR = TAG_LOG + ".KEY_FOUR";


    // Member variables
    private int mRequestCode;
    private String mUserUid;
    private MyAdapter mMyAdapter;
    private ArrayList<String> mItemMasterKeyList;
    private String mSalesHeaderKey;


    // Views
    @Bind(R.id.item_master_list)
    RecyclerView mItemMasterList;


    /**
     * Empty constructor
     */
    public LookupItemMasterListDialogFragment() {

    }


    /**
     * This is when we instantiate the fragment and pass the data
     *
     * @param requestCode       To know from where and to where to go
     * @param userUid           The user's UID
     * @param itemMasterKeyList The list of item master push() keys
     * @param salesHeaderKey    The Sales Header push() key
     * @return This fragment
     */
    public static LookupItemMasterListDialogFragment newInstance(int requestCode, String userUid, ArrayList<String> itemMasterKeyList, String salesHeaderKey) {

        // Instantiate this fragment
        LookupItemMasterListDialogFragment fragment = new LookupItemMasterListDialogFragment();

        // Instantiate the bundle
        Bundle bundle = new Bundle();

        // put the data in the bundle
        bundle.putString(KEY_DATA_USER_UID, userUid);
        bundle.putInt(KEY_DATA_REQUEST_CODE, requestCode);
        bundle.putStringArrayList(KEY_DATA_ITEM_MASTER_KEY_LIST, itemMasterKeyList);
        bundle.putString(KEY_DATA_SALES_HEADER_KEY, salesHeaderKey);

        // pass the bundle to the fragment
        fragment.setArguments(bundle);

        // return the fragment
        return fragment;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {

            // Get the user encoded email from the activity
            mUserUid = getArguments().getString(KEY_DATA_USER_UID);

            // Get the request code
            mRequestCode = getArguments().getInt(KEY_DATA_REQUEST_CODE);

            // Get the list of push() key
            mItemMasterKeyList = getArguments().getStringArrayList(KEY_DATA_ITEM_MASTER_KEY_LIST);

            // Get SalesHeader key
            mSalesHeaderKey = getArguments().getString(KEY_DATA_SALES_HEADER_KEY);
        }

        if (savedInstanceState != null) {

            mUserUid = savedInstanceState.getString(KEY_ONE);
            mRequestCode = savedInstanceState.getInt(KEY_TWO);
            mItemMasterKeyList = savedInstanceState.getStringArrayList(KEY_THREE);
            mSalesHeaderKey = savedInstanceState.getString(KEY_FOUR);

        }
    }


    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(KEY_ONE, mUserUid);
        outState.putInt(KEY_TWO, mRequestCode);
        outState.putStringArrayList(KEY_THREE, mItemMasterKeyList);
        outState.putString(KEY_FOUR, mSalesHeaderKey);
    }


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

        // Initialize the view
        final View view = inflater.inflate(R.layout.dialog_lookup_item_master, container, false);

        // Initialize the ButterKnife
        ButterKnife.bind(this, view);

        // Set more efficient
        mItemMasterList.setHasFixedSize(true);


        /**
         * Code below is for the number of span depend device (Phone / tablet)
         * and orientation (portrait / landscape)
         */
        int columnCount;
        boolean isTablet = getResources().getBoolean(R.bool.isTablet);
        boolean isLandscape = getResources().getBoolean(R.bool.isLandscape);

        if (isTablet && isLandscape) {
            columnCount = 4;
        } else if (!isTablet && isLandscape) {
            columnCount = 3;
        } else if (isTablet && !isLandscape) {
            columnCount = 3;
        } else {
            columnCount = 2;
        }


        // Initialize the LayoutManager for item master
        GridLayoutManager layoutManager =
                new GridLayoutManager(getActivity(), columnCount, GridLayoutManager.VERTICAL, false);

        // Set the layout manager for the item master
        mItemMasterList.setLayoutManager(layoutManager);

        // Return the view object
        return view;

    }

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

        // Server reference location item master
        DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference()
                .child(mUserUid)
                .child(Constants.FIREBASE_ITEM_MASTER_LOCATION);

        // Initialize the adapter
        mMyAdapter = new MyAdapter(ItemModel.class, R.layout.adapter_each_card_in_item_lookup,
                ViewHolder.class, databaseReference, mUserUid) {

            @Override
            protected void populateViewHolder(final ViewHolder viewHolder, final ItemModel model, int position) {

                // Get the pushKey()
                DatabaseReference keyRef = getRef(viewHolder.getLayoutPosition());

                // Convert the keyRef to type String, then pass it to the UI
                final String pushKey = keyRef.getKey();

                // Get the item number
                String itemNumber = model.getItemNumber();

                // Get the item desc
                String itemDesc = model.getItemDesc();
                viewHolder.mAdapterView.getmItemDesc().setText(itemDesc);

                // Get Unit of measure
                String itemUnit = model.getUnitOfMeasure();

                // Get item price
                String itemPrice = model.getItemPrice();
                viewHolder.mAdapterView.getmItemPrice().setText(itemPrice);

                // the single click listener, the user will select an item.
                viewHolder.mAdapterView.getmRoot().setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {

                        switch (mRequestCode) {

                            case Constants.REQUEST_CODE_SALES_ADD_ITEM_LOOPUP:

                                /** When the user click on an item, send the push() key and the model to
                                 * {@link com.stockita.stockitapointofsales.activities.MainActivity#sendItemMasterData(String, ItemModel)}
                                 * To it will be passed to the {@link SalesPendingAddFormDialogFragment}
                                 */
                                ((SalesDetailPendingCallbacks) getActivity()).sendItemMasterData(pushKey, model);
                                break;

                            case Constants.REQUEST_CODE_OPEN_SALES_ADD_ITEM_LOOKUP:
                                /** When the user click on an item, send the push() key and the model to
                                 * {@link com.stockita.stockitapointofsales.salespack.openpack.OpenSalesDetailActivity#sendItemMasterData(String, ItemModel)}
                                 * To it will be passed to the {@link SalesOpenAddFormDialogFragment}
                                 */
                                ((OpenSalesHeaderListCallbacks) getActivity()).sendItemMasterData(mSalesHeaderKey, model);
                                break;
                        }


                        // cleanup, to remove the listener.
                        cleanup();

                        // Dismiss the dialog
                        getDialog().dismiss();
                    }
                });


                /**
                 * Nested recycler view for item images
                 */


                // Get the reference to the Item Image
                DatabaseReference imageRef =
                        FirebaseDatabase.getInstance().getReference()
                                .child(mAdapterUserUid)
                                .child(Constants.FIREBASE_ITEM_MASTER_IMAGE_LOCATION)
                                .child(pushKey);


                // This adapter will display only image for each element that matches the item master pushKey
                mNestedImageAdapter =
                        new FirebaseRecyclerAdapter<ItemImageModel, NestedImageViewHolder>(ItemImageModel.class, R.layout.adapter_each_card_nested_image, NestedImageViewHolder.class, imageRef) {


                            @Override
                            protected void populateViewHolder(final NestedImageViewHolder viewHolder, ItemImageModel itemImageInstance, int position) {


                                // Get the pushKey() for this image in this position
                                DatabaseReference imageKeyRef = getRef(viewHolder.getLayoutPosition());

                                // Convert the keyRef to type String, then pass it to the UI
                                final String imageKeyRefString = imageKeyRef.getKey();


                                /**
                                 * Code below will find the image from the local or server then populate them in the UI
                                 */

                                // Initialize storage
                                StorageReference imageStorageRef = FirebaseStorage.getInstance().getReferenceFromUrl("gs://stockitapointofsales.appspot.com/");
                                StorageReference imageStorageRefForUser = imageStorageRef.child(mAdapterUserUid).child(Constants.FIREBASE_ITEM_MASTER_IMAGE_LOCATION).child(pushKey);

                                // Get the file path from the model
                                String filePath = itemImageInstance.getImageUrl();

                                // Get the file Uri
                                Uri file = Uri.fromFile(new File(filePath));

                                // Get the local file
                                File localFile = new File(filePath);


                                // Check if the image available in local
                                if (localFile.exists()) {
                                    try {
                                        // Display the image
                                        Glide.with(getActivity())
                                                .load("file://" + localFile)
                                                .centerCrop()
                                                .crossFade()
                                                .into(viewHolder.mItemImageNested);
                                    } catch (Exception e) {
                                        Log.e(TAG_LOG, e.getMessage());
                                    }


                                } else {

                                    // If not available in local then download from the server
                                    imageStorageRefForUser.child(file.getLastPathSegment()).getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                                        @Override
                                        public void onSuccess(Uri uri) {

                                            try {
                                                // Display the image
                                                Glide.with(getActivity())
                                                        .load(uri)
                                                        .centerCrop()
                                                        .crossFade()
                                                        .into(viewHolder.mItemImageNested);
                                            } catch (Exception e) {
                                                Log.e(TAG_LOG, e.getMessage());
                                            }

                                        }
                                    }).addOnFailureListener(new OnFailureListener() {
                                        @Override
                                        public void onFailure(@NonNull Exception e) {
                                            Log.e(TAG_LOG, e.getMessage());
                                        }
                                    });

                                }

                            }

                            @Override
                            public void onBindViewHolder(NestedImageViewHolder holder, int position, List<Object> payloads) {
                                super.onBindViewHolder(holder, position, payloads);

                                // Add animation here..
                            }


                            @Override
                            public int getItemViewType(int position) {

                                // The layout for each element on the list
                                return R.layout.adapter_each_card_nested_image;

                            }


                            @Override

                            public NestedImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

                                // Initialize the view object
                                View nested = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
                                return new NestedImageViewHolder(nested);

                            }

                        }; // End of nested image adapter


                // For the nested item image
                LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);

                // For the nested item image
                viewHolder.mAdapterView.getmItemImage().setHasFixedSize(true);

                // For the nested item image
                viewHolder.mAdapterView.getmItemImage().setLayoutManager(linearLayoutManager);

                // For the nested item image
                viewHolder.mAdapterView.getmItemImage().setAdapter(mNestedImageAdapter);

            }


            @Override
            public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
                super.onBindViewHolder(holder, position, payloads);
                // Add animation here..
            }


            @Override
            public int getItemViewType(int position) {

                // The layout for each element in the list
                return R.layout.adapter_each_card_in_item_lookup;
            }


            /**
             * It will crash if we don't override this method, like the following code
             * @param parent        ViewGroup object
             * @param viewType      The layout xml frmo the method getItemViewType
             * @return View holder type
             */
            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

                // Initialize the view object
                View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);

                // Return the view holder and pass the view object as argument
                return new ViewHolder(view);

            }
        };


        // Set the adapter for the item master
        mItemMasterList.setAdapter(mMyAdapter);


    }


    @Override
    public void onStop() {
        super.onStop();
        // Cleanup the listeners
        if (mMyAdapter != null) {
            mMyAdapter.cleanup();
        }
    }


    /**
     * This method is to receive messages from the MainActivity inform of other
     * than onActivityForResult().
     *
     * @param message any message
     */
    public void setAnyResult(String message) {
        Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();

    }


    /**
     * View holder class for Item master
     */
    public class ViewHolder extends RecyclerView.ViewHolder {


        // Declare the custom view adapter
        @Bind(R.id.adapter_custom_view_for_item_lookup)
        AdapterViewItemLookup mAdapterView;

        /**
         * Constructor
         *
         * @param itemView Object
         */
        public ViewHolder(View itemView) {
            super(itemView);

            // Initialize the ButterKnife
            ButterKnife.bind(this, itemView);
        }
    }


    /**
     * Nested view holder class for the item image
     */
    public class NestedImageViewHolder extends RecyclerView.ViewHolder {

        // Views
        @Bind(R.id.item_image_nested)
        ImageView mItemImageNested;

        /**
         * Constructor
         *
         * @param itemView
         */
        public NestedImageViewHolder(View itemView) {
            super(itemView);

            // Initialize the butterKnife
            ButterKnife.bind(this, itemView);

        }
    }


    /**
     * Abstract class for the adapter
     */
    public abstract class MyAdapter extends FirebaseRecyclerAdapter<ItemModel, ViewHolder> {

        /**
         * The user login encoded email
         */
        protected String mAdapterUserUid;

        /**
         * This is an instance of a nested adapter to display the images
         */
        protected FirebaseRecyclerAdapter<ItemImageModel, NestedImageViewHolder> mNestedImageAdapter;


        /**
         * constructor
         *
         * @param userUid        The user's sign in UID
         */
        public MyAdapter(Class<ItemModel> modelClass, int modelLayout, Class<ViewHolder> viewHolderClass, Query ref, String userUid) {
            super(modelClass, modelLayout, viewHolderClass, ref);
            this.mAdapterUserUid = userUid;

        }


        /**
         * Call super and then invoke cleanup() for the nested adapter
         */
        @Override
        public void cleanup() {
            super.cleanup();

            // invoke cleanup() on the nested image adapter
            if (mNestedImageAdapter != null) {
                mNestedImageAdapter.cleanup();
            }
        }
    }
}