package kz.arta.synergy.workflow.mobile.android.forms.general.components.repeat.days;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import kz.arta.synergy.workflow.mobile.android.R;
import kz.arta.synergy.workflow.mobile.android.common.requests.RestClient;
import kz.arta.synergy.workflow.mobile.android.common.utils.Fonts;
import kz.arta.synergy.workflow.mobile.android.common.utils.Utils;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.repeat.RepeatModel;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.repeat.RepeatPeriodConst;
import kz.arta.synergy.workflow.mobile.android.forms.general.components.users.UsersChooserConst;

/**
 * Created by neox on 25.04.16.
 * Список для выбора дня
 */
public class DayList {

    /**
     * Список месяцев в году
     */
    private String[] monthArray;

    /**
     * Экран из которого происходит запуск компонента
     */
    private Activity activity;

    /**
     * Текущий выбранный месяц
     */
    private int currentMonth;

    /**
     * Список дней на весь год для каждого месяца
     */
    private List<List<RepeatModel>> dayData;

    /**
     * Основная таблица со списком дней
     */
    private GridView daysTable;

    /**
     * Адаптер для списка дней
     */
    private DayAdapter dayAdapter;

    /**
     * Выделенные дни в данный момент
     */
    private List<RepeatModel> selectedItems;

    /**
     * Таблица с выделенными днями
     */
    private GridView selectedTable;

    /**
     * Тип текущего компонента
     */
    private int type;

    /**
     * Выделенные элементы
     */
    private String[] selected;

    /**
     * Инициализация
     */
    public void init() {

        monthArray = activity.getResources().getStringArray(R.array.repeat_period_month);

        if (type == RepeatPeriodConst.DAYS) {
            (activity.findViewById(R.id.repeat_period_select_month_panel)).setVisibility(View.GONE);
            (activity.findViewById(R.id.repeat_period_days_selected_grid_view)).setVisibility(View.GONE);
            currentMonth = 0;
        } else {
            (activity.findViewById(R.id.repeat_period_days_selected_grid_view)).setVisibility(View.VISIBLE);
            currentMonth = Calendar.getInstance().get(Calendar.MONTH);
        }

        initData();

        final TextView month = (TextView) activity.findViewById(R.id.repeat_period_select_month);
        month.setText(monthArray[currentMonth]);
        month.setTypeface(Fonts.getMedium(activity));
        month.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
                dialog.setItems(monthArray, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        setMonth(month, which);
                    }
                });
                dialog.show();
            }
        });

        ImageView prevMonth = (ImageView) activity.findViewById(R.id.repeat_period_prev_month_icon);
        prevMonth.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                leftButton(month);
            }
        });

        ImageView nextMonth = (ImageView) activity.findViewById(R.id.repeat_period_next_month_icon);
        nextMonth.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                rightButton(month);
            }
        });

        dayAdapter = new DayAdapter(dayData.get(currentMonth));

        // таблица со списком дней в месяце
        daysTable = (GridView) activity.findViewById(R.id.repeat_period_days_grid_view);
        daysTable.setAdapter(dayAdapter);
        daysTable.setVisibility(View.VISIBLE);
        daysTable.setNumColumns(GridView.AUTO_FIT);
        daysTable.setColumnWidth(Utils.convertDpToPixel(40, activity));

        MyGestureListener listener = new MyGestureListener(activity);
        listener.setSwipeGestureCallBack(new SwipeGestureCallBack() {
            @Override
            public void onSwipe(int direction) {
                if (type != RepeatPeriodConst.YEARS) {
                    return;
                }
                if (direction == MyGestureListener.LEFT) {
                    leftButton(month);
                } else if (direction == MyGestureListener.RIGHT) {
                    rightButton(month);
                }
            }

            @Override
            public void onTap(final int index) {
                dayData.get(currentMonth).get(index).setChecked(!dayData.get(currentMonth).get(index).isChecked());
                updateTables();
            }
        });

        daysTable.setOnTouchListener(listener);

        // таблица с выделенными днями
        selectedTable = (GridView) activity.findViewById(R.id.repeat_period_days_selected_grid_view);
        selectedTable.setNumColumns(GridView.AUTO_FIT);
        selectedTable.setColumnWidth(Utils.convertDpToPixel(65, activity));
        selectedTable.setVerticalSpacing(Utils.convertDpToPixel(5, activity));
        selectedTable.setHorizontalSpacing(Utils.convertDpToPixel(5, activity));
        selectedTable.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
                AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
                dialog.setMessage(activity.getString(R.string.remove_tag_question) + selectedItems.get(position).getName() + "?");
                dialog.setNegativeButton(R.string.no, null);
                dialog.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        removeTag(selectedItems.get(position).getNumber());
                    }
                });
                dialog.show();
            }
        });

        // кнопка "Готово"
        Button save = (Button) activity.findViewById(R.id.repeat_period_button_save);
        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                List<String> result = new ArrayList<>();
                for (int i = 0; i < dayData.size(); i++) {
                    for (int j = 0; j < dayData.get(i).size(); j++) {
                        if (dayData.get(i).get(j).isChecked()) {
                            if (type == RepeatPeriodConst.YEARS) {
                                result.add((j + 1) + "." + (i + 1));
                            } else {
                                result.add((j + 1) + ".0");
                            }
                        }
                    }
                }
                Intent intent = new Intent();
                intent.putExtra(UsersChooserConst.SELECTED_ITEMS, RestClient.getGson().toJson(result));
                activity.setResult(Activity.RESULT_OK, intent);
                activity.finish();
            }
        });

        updateTables();
    }

    /**
     * Метод возвращает информацию о том выделен ли хотя бы один элемент в таблице или нет
     *
     * @return true/false
     */
    private boolean hasSelected() {
        for (int i = 0; i < dayData.size(); i++) {
            for (int j = 0; j < dayData.get(i).size(); j++) {
                if (dayData.get(i).get(j).isChecked()) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Нажатие на кнопку "Предыдущий месяц"
     *
     * @param month компонент отображающий текущий месяц
     */
    public void leftButton(TextView month) {
        if (currentMonth == 0) {
            currentMonth = 11;
        } else {
            currentMonth--;
        }
        setMonth(month, currentMonth);
    }

    /**
     * Нажатие на кнопку "Следующий месяц"
     *
     * @param month компонент отображающий текущий месяц
     */
    public void rightButton(TextView month) {
        if (currentMonth == 11) {
            currentMonth = 0;
        } else {
            currentMonth++;
        }
        setMonth(month, currentMonth);
    }

    /**
     * Метод используется для обновления данных в таблицах
     */
    private void updateTables() {
        if (type == RepeatPeriodConst.YEARS) {
            activity.findViewById(R.id.repeat_period_activity_selected_title).setVisibility((hasSelected() ? View.VISIBLE : View.GONE));
            selectedItems = getSelectedItems();
            SelectedDayAdapter selectedDayAdapter = new SelectedDayAdapter(selectedItems);
            selectedTable.setAdapter(selectedDayAdapter);
        }
        dayAdapter.notifyDataSetChanged();
    }

    /**
     * Метод используется для удаления тега
     *
     * @param tagNumber номер тега
     */
    private void removeTag(int tagNumber) {
        for (int i = 0; i < dayData.size(); i++) {
            for (int j = 0; j < dayData.get(i).size(); j++) {
                if (dayData.get(i).get(j).getNumber() == tagNumber) {
                    dayData.get(i).get(j).setChecked(false);
                    updateTables();
                    break;
                }
            }
        }
    }

    /**
     * Метод обновляет на экране информацию о текущем месяце
     *
     * @param month        компонент отображающий текущий месяц
     * @param currentMonth текущий месяц
     */
    private void setMonth(TextView month, int currentMonth) {
        this.currentMonth = currentMonth;
        month.setText(monthArray[currentMonth]);
        dayAdapter = new DayAdapter(dayData.get(currentMonth));
        daysTable.setAdapter(dayAdapter);
        dayAdapter.notifyDataSetChanged();
    }

    /**
     * Метод заполняет данными список со днями
     */
    private void initData() {
        int number = 0;
        dayData = new ArrayList<>();
        for (int i = 0; i <= 11; i++) {
            int countDays = 0;
            switch (i) {
                case 0:
                case 2:
                case 4:
                case 6:
                case 7:
                case 9:
                case 11:
                    countDays = 31;
                    break;
                case 1:
                    countDays = 29;
                    break;
                case 3:
                case 5:
                case 8:
                case 10:
                    countDays = 30;
                    break;
            }
            dayData.add(new ArrayList<RepeatModel>());
            for (int j = 0; j < countDays; j++) {
                RepeatModel repeatModel = new RepeatModel();
                repeatModel.setName(String.valueOf(j + 1));
                repeatModel.setNumber(number);
                dayData.get(i).add(repeatModel);
                number++;
            }
        }
        if (selected != null && selected.length != 0) {
            if (type == RepeatPeriodConst.YEARS) {
                for (int i = 0; i < dayData.size(); i++) {
                    for (int j = 0; j < dayData.get(i).size(); j++) {
                        for (String s : selected) {
                            if (s.equals((j + 1) + "." + (i + 1))) {
                                dayData.get(i).get(j).setChecked(true);
                            }
                        }
                    }
                }
            } else {
                for (int j = 0; j < dayData.get(currentMonth).size(); j++) {
                    for (String s : selected) {
                        if (s.equals((j + 1) + ".0")) {
                            dayData.get(currentMonth).get(j).setChecked(true);
                        }
                    }
                }
            }
        }
    }

    /**
     * Метод возвращает список выбранных дней
     *
     * @return список выбранных дней
     */
    private List<RepeatModel> getSelectedItems() {
        List<RepeatModel> result = new ArrayList<>();
        for (int i = 0; i < dayData.size(); i++) {
            for (int j = 0; j < dayData.get(i).size(); j++) {
                if (dayData.get(i).get(j).isChecked()) {
                    RepeatModel day = new RepeatModel();
                    day.setChecked(true);
                    day.setNumber(dayData.get(i).get(j).getNumber());
                    day.setName(j + 1 + " " + monthArray[i].substring(0, 3).toLowerCase());
                    result.add(day);
                }
            }
        }
        return result;
    }

    public void setActivity(Activity activity) {
        this.activity = activity;
    }

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

    public void setSelected(String[] selected) {
        this.selected = selected;
    }

    public interface SwipeGestureCallBack {

        /**
         * Метод вызывается при свайпе таблицы
         *
         * @param direction направление
         */
        void onSwipe(int direction);

        /**
         * Тап по элементу
         *
         * @param index номер элемента
         */
        void onTap(int index);
    }

    /**
     * Адаптер для таблицы с днями
     */
    private class DayAdapter extends ArrayAdapter<RepeatModel> {

        /**
         * Список дней
         */
        private List<RepeatModel> days;

        /**
         * Конструктор
         *
         * @param days список дней
         */
        public DayAdapter(List<RepeatModel> days) {
            super(activity, R.layout.day_item, days);
            this.days = days;
        }

        @Override
        public View getView(int position, View someView, ViewGroup arg2) {
            LayoutInflater inflater = LayoutInflater.from(activity);
            if (someView == null) {
                someView = inflater.inflate(R.layout.day_item, arg2, false);
            }
            TextView name = (TextView) someView.findViewById(R.id.day_item_name);
            name.setText(days.get(position).getName());
            name.setTypeface(Fonts.getRoman(activity));
            View view = someView.findViewById(R.id.day_item_background);
            view.setBackgroundResource((days.get(position).isChecked() ? R.drawable.choice_selected : R.drawable.choice_unselected));
            return someView;
        }
    }

    /**
     * Адаптер для таблицы с выбранными днями
     */
    private class SelectedDayAdapter extends ArrayAdapter<RepeatModel> {

        /**
         * Список выделенных дней
         */
        private List<RepeatModel> days;

        /**
         * Конструктор
         *
         * @param weeks список выделенных дней
         */
        public SelectedDayAdapter(List<RepeatModel> weeks) {
            super(activity, R.layout.day_item, weeks);
            this.days = weeks;
        }

        @Override
        public View getView(int position, View someView, ViewGroup arg2) {
            LayoutInflater inflater = LayoutInflater.from(activity);
            if (someView == null) {
                someView = inflater.inflate(R.layout.item_selected_users, arg2, false);
            }
            TextView name = (TextView) someView.findViewById(R.id.name_selected_users);
            name.setText(days.get(position).getName());
            name.setTypeface(Fonts.getRoman(activity));
            return someView;
        }
    }

    /**
     * Свайп по таблице
     */
    public class MyGestureListener implements View.OnTouchListener {

        /**
         * Свайп влево
         */
        public static final int LEFT = 1;

        /**
         * Свайп вправо
         */
        public static final int RIGHT = 2;

        /**
         * Класс для работы с жестами
         */
        private GestureDetector detector;

        /**
         * CallBack
         */
        private SwipeGestureCallBack callBack;

        public MyGestureListener(Context context) {
            detector = new GestureDetector(context, new MyGestureDetector());
        }

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return detector.onTouchEvent(event);
        }

        public void setSwipeGestureCallBack(SwipeGestureCallBack callBack) {
            this.callBack = callBack;
        }

        class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {

            private static final int SWIPE_MIN_DISTANCE = 20;
            private static final int SWIPE_THRESHOLD_VELOCITY = 100;

            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                if (Math.abs(e1.getX() - e2.getX()) > Math.abs(e1.getY() - e2.getY())) {
                    if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                        callBack.onSwipe(RIGHT);
                    } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                        callBack.onSwipe(LEFT);
                    }
                }
                return false;
            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                callBack.onTap(daysTable.pointToPosition((int) e.getX(), (int) e.getY()));
                return true;
            }

            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }
        }
    }
}
