package com.hikapro.backpack.model;


import android.os.Message;
import android.widget.Toast;

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

import com.hikapro.backpack.App;
import com.hikapro.backpack.R;
import com.hikapro.backpack.model.dao.Command;
import com.hikapro.backpack.model.dao.DAO;
import com.hikapro.backpack.model.dao.Event;
import com.hikapro.backpack.model.entities.Category;
import com.hikapro.backpack.model.entities.Item;
import com.hikapro.backpack.presenter.Presenter;
import com.hikapro.backpack.presenter.adapters.helper.AppRater;

/**
 * Created by tariel on 22/04/16.
 */
public class ItemModel implements Model.Item {

    protected Presenter.ItemList  presenter;

    protected DAO               dao;
    protected int               currentSet;
    protected int               currentSetActiveItemsQty;
    protected int               packedQty;
    protected Hashtable<Integer, Category>      categoriesCache;
    protected List<Item>        itemsCache;

    protected Hashtable<Category, List<Item>> items;
    protected int lastVisiblePosition;

    public ItemModel() {
        this.categoriesCache    = new Hashtable<>(20, 0.9f);
        this.itemsCache         = new ArrayList<>(256);

        this.packedQty          = -1;
        this.dao                = DAO.getInstance();
    }

    @Override
    public void onEvent(Message event) {

        switch (event.what) {
            case Event.SET_ITEMS_LOAD_ERROR : // TODO check
                if (presenter != null) {
                    if (packedQty == -1)
                        packedQty = presenter.getCurrentSet().getPackedQty();
                    presenter.notifyItemPackStatusChanged();
                }
                break;
            case Event.SET_UNPACK_ERROR :
                break;
            case Event.SET_RESTORE_ERROR :
                break;
            case Event.SET_GET_STAT_ERROR:
                break;
            case Event.ITEM_FROM_SET_ERROR :
                break;
            case Event.ITEM_DELETE_ERROR :
                break;
            case Event.ITEM_PACK_ERROR :
                break;
            case Event.ITEM_UNPACK_ERROR :
                break;
            case Event.ITEM_INSERT_ERROR :
                break;
            case Event.ITEM_PENDING_REMOVAL_ERROR:
                break;
            case Event.ITEM_REMOVAL_CANCEL_ERROR:
                break;
            case Event.ITEM_CATEGORY_LOAD_ERROR :
                break;
            case Event.SET_ITEMS_LIKE_ERROR:
                if (!itemsCache.isEmpty()) {
                    itemsCache.clear();
                }
                notifyDataSetChanged();
                break;
            case Event.SET_ITEMS_LOAD_COMPLETED:
                itemsCache = (List<Item>) event.obj;
                notifyDataSetChanged();
                break;
            case Event.SET_ITEMS_LIKE_COMPLETED:
                itemsCache = (List<Item>) event.obj;
                notifyDataSetChanged();
                break;
            case Event.SET_GET_STAT_COMPLETED:
                currentSetActiveItemsQty = event.arg1;
                packedQty = event.arg2;
                if (presenter != null)
                    presenter.notifyItemPackStatusChanged();
                break;
            case Event.ITEM_PENDING_REMOVAL_COMPLETED:
                executeQuery();
                break;
            case Event.ITEM_REMOVAL_CANCELED:
                executeQuery();
                break;
            case Event.ITEM_READ_COMPLETED:
                itemsCache.add((Item) event.obj);
                Collections.sort(itemsCache);
                notifyDataSetChanged();
                break;
            case Event.SET_UNPACK_COMPLETED:
                executeQuery();
                break;
            case Event.ITEM_CATEGORY_LOAD_COMPLETED:
                categoriesCache = (Hashtable<Integer, Category>)event.obj;
                break;
            case Event.ITEM_FROM_SET_DELETED:
                executeQuery();
                break;
            case Event.ITEM_DELETED :
                break;
            case Event.ITEM_PACKED :
                executeQuery();
                break;
            case Event.ITEM_UNPACKED :
                executeQuery();
                break;
            case Event.ITEM_INSERTED :
                break;
            case Event.SET_RESTORE_COMPLETED:
                executeQuery();
                Toast.makeText(App.getAppContext(), R.string.restore_completed, Toast.LENGTH_SHORT).show();
                break;
            case Event.NEED_TO_RATE_NOW:
                if (presenter != null)
                    presenter.showRateDialog();
                break;
        }
    }

    @Override
    public void executeQuery() {
        Message command;
        dao.registerObserver(this);

        command = Message.obtain();
        command.what = Command.SET_CLEAN_PACKED;
        command.arg1 = currentSet;
        dao.executeCommand(command);

        if (categoriesCache == null || categoriesCache.isEmpty()) {
            command = Message.obtain();
            command.what = Command.ITEM_GET_CATEGORIES;
            dao.executeCommand(command);
        }
        command = Message.obtain();
        command.what = Command.SET_GET_ITEMS;
        command.arg1 = currentSet;
        dao.executeCommand(command);

        command = Message.obtain();
        command.what = Command.SET_GET_STAT;
        command.arg1 = presenter.getCurrentSet().getId();
        dao.executeCommand(command);
    }

    @Override
    public Category getCategoryByPosition(int position) {
        Category ret = null;
        ret = categoriesCache.get(itemsCache.get(position).getCategory());
        return ret;

    }

    public int getLastVisiblePosition() {
        return lastVisiblePosition < 0 ? 0 : lastVisiblePosition;
    }

    public void setLastVisiblePosition(int lastVisiblePosition) {
        this.lastVisiblePosition = lastVisiblePosition;
    }

    @Override
    public Item getItemByPosition(int position) {
        Item ret = null;
        ret = itemsCache.get(position);
        return ret;
    }

    @Override
    public void filter(String query) {

        if (query.isEmpty()) {
            Message command = Message.obtain();
            command.what = Command.SET_GET_ITEMS;
            command.arg1 = presenter.getCurrentSet().getId();
            dao.executeCommand(command);
        } else {
            Message command = Message.obtain();
            command.what = Command.SET_GET_ITEMS_LIKE;
            command.arg1 = presenter.getCurrentSet().getId();
            command.obj = query;
            dao.executeCommand(command);
        }
    }

    @Override
    public int getHeaderId(int position) {
        return itemsCache.get(position).getCategory();
    }

    @Override
    public int getItemId(int position) {
        return itemsCache.get(position).getId();
    }

    @Override
    public int getItemsCount() {
        return  itemsCache == null ? 0 : itemsCache.size();
    }

    @Override
    public int getActiveItemsCount() {
        return currentSetActiveItemsQty;
    }

    @Override
    public int getPackedQty() {
        return packedQty;
    }

    @Override
    public void notifyDataSetChanged() {
        if (presenter != null)
            presenter.notifyDataSetChanged();
    }

    @Override
    public void onDestroy(boolean isConfigurationChanging) {
        if ( !isConfigurationChanging ) {
            presenter = null;
            categoriesCache = null;
            itemsCache = null;
        }
        dao.unregisterObserver(this);
    }

    @Override
    public void pendingRemove(Item item) {
        if (item != null) {
            Message command = Message.obtain();
            command.what = Command.ITEM_PENDING_REMOVAL;
            command.arg1 = currentSet;
            command.arg2 = item.getId();
            dao.executeCommand(command);
        }
    }

    @Override
    public void pendingRemoveCancel(Item item) {
        if (item != null) {
            Message command = Message.obtain();
            command.what = Command.ITEM_REMOVAL_CANCEL;
            command.arg1 = currentSet;
            command.arg2 = item.getId();
            dao.executeCommand(command);
        }
    }

    @Override
    public void remove(Item item) {
        if (item != null) {
            Message command = Message.obtain();
            command.what = Command.ITEM_DELETE_FROM_SET;
            command.arg1 = currentSet;
            command.arg2 = item.getId();
            dao.executeCommand(command);
        }
    }
    @Override
    public void packItem(com.hikapro.backpack.model.entities.Item item) {
        if (item != null) {
            itemsCache.remove(item);
            Message command = Message.obtain();
            command.what = Command.ITEM_PACK;
            command.arg1 = currentSet;
            command.arg2 = item.getId();
            dao.executeCommand(command);
        }
    }

    @Override
    public void unpackItem(com.hikapro.backpack.model.entities.Item item) {
        // nothing
    }

    @Override
    public void unpackSet(int setId) {
        Message command;
        command = Message.obtain();
        command.what = Command.SET_UNPACK_ITEMS;
        command.arg1 = setId;
        dao.executeCommand(command);
    }

    @Override
    public void restoreSet(int setId) {
        Message command;
        command = Message.obtain();
        command.what = Command.SET_RESTORE_DEFAULT;
        command.arg1 = presenter.getCurrentSet().getId();
        dao.executeCommand(command);
    }


    @Override
    public void setPresenter(Presenter.ItemList presenter) {
        this.presenter      = presenter;
        this.currentSet     = presenter.getCurrentSet().getId();
        this.currentSetActiveItemsQty = presenter.getCurrentSet().getActiveQty();
    }

    @Override
    public Presenter.ItemList getPresenter() {
        return presenter;
    }

}
