package kz.arta.synergy.workflow.mobile.android.forms.general.components.users.activity;

import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.google.gson.reflect.TypeToken;
import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
import com.pnikosis.materialishprogress.ProgressWheel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import kz.arta.synergy.workflow.mobile.android.R;
import kz.arta.synergy.workflow.mobile.android.common.ActivityConst;
import kz.arta.synergy.workflow.mobile.android.common.components.SearchEditText;
import kz.arta.synergy.workflow.mobile.android.common.models.Person;
import kz.arta.synergy.workflow.mobile.android.common.requests.RestClient;
import kz.arta.synergy.workflow.mobile.android.common.requests.SendGetRequest;
import kz.arta.synergy.workflow.mobile.android.common.utils.ActionUtils;
import kz.arta.synergy.workflow.mobile.android.common.utils.Const;
import kz.arta.synergy.workflow.mobile.android.common.utils.Fonts;
import kz.arta.synergy.workflow.mobile.android.common.utils.FragmentConst;
import kz.arta.synergy.workflow.mobile.android.common.utils.HorizontalListView;
import kz.arta.synergy.workflow.mobile.android.common.utils.Utils;
import kz.arta.synergy.workflow.mobile.android.files.adapters.AdapterPath;
import kz.arta.synergy.workflow.mobile.android.files.models.Path;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.users.UsersChooserConst;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.users.adapters.UsersChooserAdapter;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.users.model.DepartmentModel;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.users.model.GroupsModel;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.users.model.UserModel;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.users.navigator.UsersChooserNavigatorItem;

/**
 * Created by neox on 17.03.16.
 * Юзер чузер
 */
public class UsersChooserActivity extends Activity {

    /**
     * Активити
     */
    private Activity activity;

    /**
     * Прогрессбар
     */
    private ProgressWheel progressBar;

    /**
     * Авторизированный пользователь
     */
    private Person person;

    /**
     * Боковая навигация
     */
    private SlidingMenu slidingMenu;

    /**
     * Адаптер для списка пользователей
     */
    private UsersChooserAdapter usersAdapter;

    /**
     * Пользователи в списке
     */
    private List<UserModel> usersArray;

    /**
     * Выбранные пользователи
     */
    private List<UserModel> selectedUsers;

    /**
     * Данные компонента "Путь"
     */
    private List<Path> pathData;

    /**
     * Адаптер компонента "Путь"
     */
    private BaseAdapter pathAdapter;

    /**
     * Компонент "Путь"
     */
    private HorizontalListView pathList;

    /**
     * Тип текущих пользователей
     *
     * @see UsersChooserConst#SELECTED_USERS
     * @see UsersChooserConst#OFTEN_USERS
     * @see UsersChooserConst#GROUPS
     * @see UsersChooserConst#DEPARTMENTS
     */
    private int type;

    /**
     * Контейнер с навигатором
     */
    private LinearLayout navigatorLayout;

    /**
     * Компонент для поиска
     */
    private SearchEditText searchEditText;

    /**
     * Ссылка на текущий список пользователей
     */
    private String url;

    /**
     * С какой записи загружать пользователей
     */
    private int startRecord = 0;

    /**
     * Загружается ли список в данный момент
     */
    private boolean isLoading = false;

    /**
     * Используется ли мультивыбор
     */
    private boolean multiSelect;

    /**
     * Отображать ли группы
     */
    private boolean showGroups;

    /**
     * Отображать ли удаленных пользователей
     */
    private boolean showRemoved;

    /**
     * Фильтрация по departmentID
     */
    private String filterDepartmentID;

    /**
     * Фильтрация по positionID
     */
    private String filterPositionID;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.users_chooser_activity);

        activity = this;

        ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }

        Intent intent = getIntent();
        person = (Person) intent.getSerializableExtra(ActivityConst.PERSON);
        multiSelect = intent.getBooleanExtra(UsersChooserConst.MULTI_SELECT, false);
        showGroups = intent.getBooleanExtra(UsersChooserConst.SHOW_GROUPS, false);
        showRemoved = intent.getBooleanExtra(UsersChooserConst.SHOW_REMOVED, false);
        filterDepartmentID = intent.getStringExtra(UsersChooserConst.FILTER_DEPARTMENT_ID);
        filterPositionID = intent.getStringExtra(UsersChooserConst.FILTER_POSITION_ID);
        selectedUsers = RestClient.getGson().fromJson(intent.getStringExtra(UsersChooserConst.SELECTED_ITEMS),
                new TypeToken<List<UserModel>>() {
                }.getType());

        if (selectedUsers != null) {
            for (UserModel user : selectedUsers) {
                user.setIsChecked(true);
            }
        }

        init();
    }

    /**
     * Инициализация компонентов
     */
    private void init() {

        ((TextView) findViewById(R.id.users_chooser_action_bar_title)).setText(R.string.users);

        progressBar = (ProgressWheel) findViewById(R.id.user_chooser_progress_bar);

        ImageView showNavigator = (ImageView) findViewById(R.id.user_chooser_icon_show_navigator);
        showNavigator.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                slidingMenu.toggle();
            }
        });

        // компонент "Путь"
        pathData = new ArrayList<>();
        pathAdapter = new AdapterPath(activity, pathData);
        pathList = (HorizontalListView) findViewById(R.id.list_view_path_user_chooser);
        pathList.setAdapter(pathAdapter);
        pathList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                // все элементы отмечаем как "невыделенные"
                for (Path path : pathData) {
                    path.setSelected(false);
                }
                // говорим элемент, по которому происходит тап - будет выделен
                pathData.get(i).setSelected(true);
                searchListItem(navigatorLayout, pathData.get(i).getNodeID());
            }
        });

        // компонент для поиска
        searchEditText = (SearchEditText) findViewById(R.id.search_user_edit_text);
        searchEditText.setHint(getString(R.string.search_users));
        searchEditText.setListener(new SearchEditText.SearchTextListener() {
            @Override
            public void onTextChanged(String text) {
                if (type == UsersChooserConst.DEPARTMENTS || type == UsersChooserConst.OFTEN_USERS) {
                    getUsers(url, text, type, true, false);
                } else if (type == UsersChooserConst.GROUPS) {
                    getGroups(text);
                }
            }
        });

        if (selectedUsers == null) {
            selectedUsers = new ArrayList<>();
        }

        usersArray = new ArrayList<>();
        usersAdapter = new UsersChooserAdapter(this, usersArray, multiSelect);

        // основной список
        ListView users = (ListView) findViewById(R.id.users_list);
        users.setAdapter(usersAdapter);
        users.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                if (multiSelect) {
                    if (!usersArray.get(i).isChecked()) {
                        selectedUsers.add(usersArray.get(i));
                    } else {
                        String userID = usersArray.get(i).getPersonID();
                        int foundIndex = -1;
                        for (int k = 0; k < selectedUsers.size(); k++) {
                            if (userID.equals(selectedUsers.get(k).getPersonID())) {
                                foundIndex = k;
                            }
                        }
                        selectedUsers.remove(foundIndex);
                    }
                    usersArray.get(i).setIsChecked(!usersArray.get(i).isChecked());
                } else {
                    for (UserModel user : usersArray) {
                        user.setIsChecked(false);
                    }
                    usersArray.get(i).setIsChecked(true);
                    selectedUsers.clear();
                    selectedUsers.add(usersArray.get(i));
                }
                usersAdapter.notifyDataSetChanged();
            }
        });

        users.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (totalItemCount >= FragmentConst.DEFAULT_COUNT_WORKS && type != UsersChooserConst.SELECTED_USERS) {
                    final int lastItem = firstVisibleItem + visibleItemCount;
                    if (lastItem == totalItemCount) {
                        if (!isLoading) {
                            isLoading = true;
                            startRecord += FragmentConst.DEFAULT_COUNT_WORKS;
                            getUsers(ActionUtils.parseWorkUrl(url, startRecord), "", type, false, false);
                        }
                    }
                }
            }

            @Override
            public void onScrollStateChanged(AbsListView absListView, int i) {
            }
        });

        users.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (multiSelect && (type == UsersChooserConst.DEPARTMENTS || type == UsersChooserConst.OFTEN_USERS)) {
                    showSelectDialog();
                }
                return true;
            }
        });

        // боковая навигация
        View view = getLayoutTree();
        slidingMenu = new SlidingMenu(getApplicationContext());
        slidingMenu.setMode(SlidingMenu.RIGHT);
        slidingMenu.attachToActivity(activity, SlidingMenu.SLIDING_CONTENT);
        slidingMenu.setMenu(view);
        slidingMenu.setBehindWidth(Utils.convertDpToPixel(Const.SLIDING_MENU_WIDTH, activity));

        navigatorLayout = (LinearLayout) view.findViewById(R.id.filters_list);

        // главный контейнер фильтров
        final SwipeRefreshLayout filtersScroll = (SwipeRefreshLayout) view.findViewById(R.id.refresh_filters);
        filtersScroll.setEnabled(false);

        getSelectedUsers(navigatorLayout);

        getOftenUsers(navigatorLayout);

        // отображать ли группы
        if (showGroups) {
            getGroups(navigatorLayout);
        }

        getDepartments(navigatorLayout);

        // кнопка "Сохранить"
        Button save = (Button) findViewById(R.id.user_chooser_activity_save);
        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra(UsersChooserConst.SELECTED_ITEMS, RestClient.getGson().toJson(selectedUsers));
                setResult(RESULT_OK, intent);
                finish();
            }
        });
    }

    /**
     * Метод вызывается при долгом тапе на плашку
     */
    private void showSelectDialog() {
        final boolean all = isAllUsersSelected();
        String[] selectAll = {getString(R.string.select_all_users)};
        final String[] cancelAll = {getString(R.string.cancel_all_users)};
        AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
        dialog.setTitle(getString(R.string.users));
        dialog.setItems((!all ? selectAll : cancelAll), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int item) {
                if (all) {
                    cancelAllUsers();
                } else {
                    selectAllUsers();
                }
            }
        });
        dialog.setCancelable(true);
        dialog.show();
    }

    /**
     * Метод выделяет всех пользователей в списке
     */
    private void selectAllUsers() {
        int index1 = url.indexOf("&recordsCount=") + 14;
        int index2 = url.indexOf("&showAll=");
        StringBuilder str = new StringBuilder(url);
        str.replace(index1, index2, "-1");
        getUsers(str.toString(), "", type, true, true);
    }

    /**
     * Метод развыделяет всех пользователей в списке
     */
    private void cancelAllUsers() {
        for (int i = 0; i < usersArray.size(); i++) {
            usersArray.get(i).setIsChecked(false);
        }
        selectedUsers.clear();
        usersAdapter.notifyDataSetChanged();
    }

    /**
     * Метод проверяет все ли выделены пользователи в списке
     *
     * @return true/false
     */
    private boolean isAllUsersSelected() {
        for (int i = 0; i < usersArray.size(); i++) {
            if (!usersArray.get(i).isChecked()) {
                return false;
            }
        }
        return true;
    }

    /**
     * Метод вызывается при нажатии на элемент пути
     *
     * @param layout контейнер
     * @param uuid   идентификатор элемента
     */
    private void searchListItem(LinearLayout layout, String uuid) {
        for (int i = 0; i < layout.getChildCount(); i++) {
            if (layout.getChildAt(i) instanceof UsersChooserNavigatorItem) {
                UsersChooserNavigatorItem node = (UsersChooserNavigatorItem) layout.getChildAt(i);
                if (uuid == null && node.getType() == type) {
                    node.setSelected();
                    node.tapItem();
                    return;
                } else if (node.getDepartmentID() != null && node.getType() == type && node.getDepartmentID().equals(uuid)) {
                    node.setSelected();
                    node.tapItem();
                    return;
                } else if (node.getGroupID() != 0 && node.getType() == type && String.valueOf(node.getGroupID()).equals(uuid)) {
                    node.setSelected();
                    node.tapItem();
                    return;
                }
                searchListItem(node, uuid);
            }
        }
    }

    /**
     * Метод заполняет данными компонент "путь"
     *
     * @param pathItems элементы пути
     */
    public void initPath(List<UserModel> pathItems) {
        // очистка пути
        pathData.clear();
        for (int i = 0; i < pathItems.size(); i++) {
            Path path = new Path();
            path.setName(pathItems.get(i).getDepartmentName());
            path.setNodeID(pathItems.get(i).getUuid());
            pathData.add(path);
            if (i == pathItems.size() - 1) {
                path.setSelected(true);
            }
        }
        // обновляем компонент
        pathAdapter.notifyDataSetChanged();
        // скроллим список до конца
        pathList.scrollTo(Integer.MAX_VALUE);
    }

    /**
     * Метод возвращает view навигатора
     *
     * @return view
     */
    private View getLayoutTree() {
        LayoutInflater ltInflater = getLayoutInflater();
        View view = ltInflater.inflate(R.layout.fragment_filters, null, false);
        (view.findViewById(R.id.sync_button_title)).setVisibility(View.GONE);
        (view.findViewById(R.id.sync_icon)).setVisibility(View.GONE);
        (view.findViewById(R.id.sync_button)).setVisibility(View.GONE);
        (view.findViewById(R.id.icon_settings)).setVisibility(View.GONE);
        ((TextView) view.findViewById(R.id.title_action_bar_filters)).setTypeface(Fonts.getMedium(activity));
        return view;
    }

    /**
     * Метод добавляет плашку выбранных пользователей
     *
     * @param layout контейнер
     */
    private void getSelectedUsers(final LinearLayout layout) {

        UserModel userModel = new UserModel();
        userModel.setDepartmentName(getString(R.string.selected));

        List<UserModel> parents = new ArrayList<>();
        parents.add(userModel);

        UsersChooserNavigatorItem item = new UsersChooserNavigatorItem(activity);
        item.setPerson(person);
        item.setName(getString(R.string.selected));
        item.setLevel(1);
        item.setType(UsersChooserConst.SELECTED_USERS);
        item.setComponentType(UsersChooserConst.USER_CHOOSER);
        item.setHideIcon(true);
        item.setParents(parents);
        item.add();

        layout.addView(item);
    }

    /**
     * Метод добавляет плашку часто выбираемых пользователей
     *
     * @param layout контейнер
     */
    private void getOftenUsers(final LinearLayout layout) {

        UserModel userModel = new UserModel();
        userModel.setDepartmentName(getString(R.string.often_selected));

        List<UserModel> parents = new ArrayList<>();
        parents.add(userModel);

        UsersChooserNavigatorItem item = new UsersChooserNavigatorItem(activity);
        item.setPerson(person);
        item.setName(getString(R.string.often_selected));
        item.setLevel(1);
        item.setParents(parents);
        item.setType(UsersChooserConst.OFTEN_USERS);
        item.setComponentType(UsersChooserConst.USER_CHOOSER);
        item.setHideIcon(true);
        item.add();

        layout.addView(item);
    }

    /**
     * Метод добавляет плашку групп
     *
     * @param layout контейнер
     */
    public void getGroups(LinearLayout layout) {

        UserModel userModel = new UserModel();
        userModel.setDepartmentName(getString(R.string.groups));

        List<UserModel> parents = new ArrayList<>();
        parents.add(userModel);

        UsersChooserNavigatorItem item = new UsersChooserNavigatorItem(activity);
        item.setPerson(person);
        item.setName(getString(R.string.groups));
        item.setLevel(1);
        item.setParents(parents);
        item.setType(UsersChooserConst.GROUPS);
        item.setComponentType(UsersChooserConst.USER_CHOOSER);
        item.add();

        layout.addView(item);
    }

    /**
     * Метод добавляет плашку департаментов
     *
     * @param layout контейнер
     */
    public void getDepartments(final LinearLayout layout) {
        new SendGetRequest("rest/api/userchooser/search_dept?departmentID=" +
                "32b36e0c-4621-4c96-99e1-3826284c363e&showChildDepartments=false", person) {
            @Override
            protected void onPostExecute(String result) {
                if (result == null) {
                    return;
                }
                try {

                    DepartmentModel[] departments = RestClient.getGson().fromJson(result, DepartmentModel[].class);

                    UserModel userModel = new UserModel();
                    userModel.setDepartmentName(departments[0].getDepartmentName());
                    userModel.setUuid(departments[0].getDepartmentID());

                    List<UserModel> parents = new ArrayList<>();
                    parents.add(userModel);

                    UsersChooserNavigatorItem item = new UsersChooserNavigatorItem(activity);
                    item.setPerson(person);
                    item.setLevel(1);
                    item.setType(UsersChooserConst.DEPARTMENTS);
                    item.setComponentType(UsersChooserConst.USER_CHOOSER);
                    item.setName(departments[0].getDepartmentName());
                    item.setDepartmentID(departments[0].getDepartmentID());
                    item.setParents(parents);
                    item.add();
                    item.setSelected();
                    item.expand();
                    item.tapItem();

                    layout.addView(item);

                } catch (Exception exc) {
                    // handling error...
                }
            }
        }.execute();
    }

    /**
     * Метод добавляет в список выбранных пользователей
     */
    public void getSelected() {
        this.type = UsersChooserConst.SELECTED_USERS;
        searchEditText.setVisibility(View.GONE);
        try {
            usersArray.clear();
            for (UserModel user : selectedUsers) {
                usersArray.add(user);
            }
            usersAdapter.notifyDataSetChanged();
        } catch (Exception exc) {
            // handling error...
        }
    }

    /**
     * Метод загружает группы
     *
     * @param searchText строка поиска
     */
    public void getGroups(String searchText) {
        type = UsersChooserConst.GROUPS;
        searchEditText.setVisibility(View.VISIBLE);
        new SendGetRequest("rest/api/groups/find?startRecord=0&recordsCount=30&search=" + searchText, person) {
            @Override
            protected void onPostExecute(String result) {
                if (result == null) {
                    return;
                }
                try {
                    usersArray.clear();
                    isLoading = true;
                    GroupsModel groupsModel = RestClient.getGson().fromJson(result, GroupsModel.class);
                    for (int i = 0; i < groupsModel.getArray().length; i++) {
                        UserModel userModel = new UserModel();
                        userModel.setPersonName(groupsModel.getArray()[i].name);
                        userModel.setPositionName(groupsModel.getArray()[i].parentName);
                        userModel.setPersonID(String.valueOf(groupsModel.getArray()[i].groupID));
                        usersArray.add(userModel);
                    }
                    for (int i = 0; i < usersArray.size(); i++) {
                        for (int j = 0; j < selectedUsers.size(); j++) {
                            String userID = usersArray.get(i).getPersonID();
                            String selectedUseID = selectedUsers.get(j).getPersonID();
                            if (userID.equals(selectedUseID)) {
                                usersArray.get(i).setIsChecked(true);
                            }
                        }
                    }
                    usersAdapter.notifyDataSetChanged();
                } catch (Exception exc) {
                    // handling error...
                }
            }
        }.execute();
    }

    /**
     * Метод загружает список пользователей по указанному url
     *
     * @param url        url на список пользователей
     * @param searchText поисковая строка
     * @param type       тип текущих пользователей
     * @param newSearch  используется ли новый поиск
     * @param selectAll  выделить ли всех пользователей в списке после выполнения запроса
     */
    public void getUsers(String url, String searchText, int type, boolean newSearch, final boolean selectAll) {
        this.type = type;
        this.url = url;
        searchEditText.setVisibility(type == UsersChooserConst.OFTEN_USERS ? View.GONE : View.VISIBLE);
        if (newSearch) {
            startRecord = 0;
            url = ActionUtils.parseWorkUrl(url, startRecord);
            usersArray.clear();
        }
        new SendGetRequest(url + "&showNoPosition=" + (showRemoved ? "true" : "false") +
                (filterPositionID != null && !filterPositionID.equals("null") ? "&filterPositionID=" + filterPositionID : "") +
                (filterDepartmentID != null && !filterDepartmentID.equals("null") ? "&filterDepartmentID=" + filterDepartmentID : "") +
                "&search=" + (!searchText.isEmpty() ? searchText : ""), person) {
            @Override
            protected void onPreExecute() {
                progressBar.setVisibility(View.VISIBLE);
                super.onPreExecute();
            }

            @Override
            protected void onPostExecute(String result) {
                progressBar.setVisibility(View.GONE);
                if (result == null) {
                    return;
                }
                try {
                    UserModel[] users = RestClient.getGson().fromJson(result, UserModel[].class);
                    isLoading = users.length == 0;
                    Collections.addAll(usersArray, users);
                    if (selectAll) {
                        selectedUsers.clear();
                        for (int i = 0; i < usersArray.size(); i++) {
                            usersArray.get(i).setIsChecked(true);
                            selectedUsers.add(usersArray.get(i));
                        }
                        isLoading = true;
                    }
                    for (int i = 0; i < usersArray.size(); i++) {
                        for (int j = 0; j < selectedUsers.size(); j++) {
                            String userID = usersArray.get(i).getPersonID();
                            String selectedUseID = selectedUsers.get(j).getPersonID();
                            if (userID.equals(selectedUseID)) {
                                usersArray.get(i).setIsChecked(true);
                            }
                        }
                    }
                    usersAdapter.notifyDataSetChanged();
                } catch (Exception exc) {
                    // handling error...
                }
            }
        }.execute();
    }

    @Override
    public void onBackPressed() {
        if (slidingMenu.isMenuShowing()) {
            hideMenu();
        } else {
            super.onBackPressed();
        }
    }

    public void hideMenu() {
        slidingMenu.toggle();
    }

    public void setType(int type) {
        this.type = type;
    }
}
