package kz.arta.synergy.workflow.mobile.android.documents.offline;


import android.content.Context;

import com.google.gson.reflect.TypeToken;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import kz.arta.synergy.workflow.mobile.android.comments.CommentConst;
import kz.arta.synergy.workflow.mobile.android.comments.models.CommentItem;
import kz.arta.synergy.workflow.mobile.android.common.models.Person;
import kz.arta.synergy.workflow.mobile.android.common.offline.get.FormCompletionTable;
import kz.arta.synergy.workflow.mobile.android.common.offline.get.LogsTable;
import kz.arta.synergy.workflow.mobile.android.common.offline.get.WorkActionsTable;
import kz.arta.synergy.workflow.mobile.android.common.offline.get.WorkCommentsTable;
import kz.arta.synergy.workflow.mobile.android.common.offline.get.WorksTable;
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.DateUtils;
import kz.arta.synergy.workflow.mobile.android.common.utils.MyApplication;
import kz.arta.synergy.workflow.mobile.android.documents.common.models.DocumentItem;
import kz.arta.synergy.workflow.mobile.android.documents.common.models.FiltersDocumentItem;
import kz.arta.synergy.workflow.mobile.android.works.models.CompletionFormItem;
import kz.arta.synergy.workflow.mobile.android.works.models.WorkItem;

/**
 * Created by neox on 22.08.16.
 * Синхронизация документов
 */
public class DocumentSync {

    private SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.DEFAULT_DATE_JOURNAL_SYNC);
    private LogsTable offlineLogs;
    private double random;

    private Person person;
    private SendGetRequest sendGetRequest;
    private List<FiltersDocumentItem> filtersList;

    private DocumentTable documentsTable;
    private DocumentFiltersTable documentFiltersTable;
    private DocumentCommentsTable documentCommentsTable;
    private DocumentAttachmentsTable documentAttachmentsTable;
    private WorksTable works;
    private WorkCommentsTable comments;
    private WorkActionsTable actions;
    private FormCompletionTable formsCompletion;

    public DocumentSync(Person person, Context context, boolean fullSync, double random) {

        this.person = person;
        this.random = random;

        sendGetRequest = new SendGetRequest(person);

        filtersList = new ArrayList<>();

        offlineLogs = new LogsTable(context);
        documentsTable = new DocumentTable(context);
        documentFiltersTable = new DocumentFiltersTable(context);
        documentCommentsTable = new DocumentCommentsTable(context);
        documentAttachmentsTable = new DocumentAttachmentsTable(context);
        works = new WorksTable(context);
        comments = new WorkCommentsTable(context);
        actions = new WorkActionsTable(context);
        formsCompletion = new FormCompletionTable(context);

        if (fullSync) {
            documentsTable.removeAll();
            documentFiltersTable.removeAll();
            documentCommentsTable.removeAll();
            documentAttachmentsTable.removeAll();
        }
    }

    /**
     * Частичная синхронизация документов
     * @param key       ключ
     */
    public void listSync(String key) {
        String oldDocumentsList = documentsTable.get(key);
        String newDocumentsList = sendGetRequest.requestGET(key);
        documentsTable.update(key, newDocumentsList);
        List<DocumentItem> oldDocuments = RestClient.getGson().fromJson(oldDocumentsList, new TypeToken<List<DocumentItem>>() {}.getType());
        List<DocumentItem> newDocuments = RestClient.getGson().fromJson(newDocumentsList, new TypeToken<List<DocumentItem>>() {}.getType());
        for (DocumentItem document : oldDocuments) {
            if (document.getActions().length == 0) {
                documentCommentsTable.removeByDocumentID(document.getDocumentID());
                documentAttachmentsTable.removeByDocumentID(document.getDocumentID());
            }
        }
        for (DocumentItem document : newDocuments) {
            if (document.getActions().length == 0) {
                getComments(document);
            } else {
                for (String workID : document.getActions()) {
                    try {
                        String workStr = sendGetRequest.requestGET(person.getHost() +
                                "rest/api/workflow/works_by_id?workID=" + workID);
                        WorkItem[] work = RestClient.getGson().fromJson(workStr, WorkItem[].class);
                        WorkItem oldWork = works.getWorkInfo(workID);
                        if (oldWork.getActionID() == null && work != null && work[0] != null) {
                            work[0].setFilterID("");
                            work[0].setObjectID("");
                            work[0].setFilterType("");
                            works.addWork(work[0]);
                            getCommentsForWork(workID);
                            getActionsForWork(workID);
                            getFormCompletion(workID);
                        }
                    } catch (Exception exc) {
                        // handling error ...
                    }
                }
            }
            getAttachments(document);
        }
    }

    /**
     * Полная синхронизация документов
     */
    public void allSync() {
        getFilters(person.getHost() + "rest/api/docflow/doc/documents_filters?locale=" + MyApplication.getLang(), 1);
        getDocuments();
    }

    /**
     * Метод рекурсивно загружает фильтры документов и добавляет их в массив filtersList
     *
     * @param url   url до списка фильтров
     * @param level текущий уровень вложенности
     */
    private void getFilters(String url, int level) {
        String filtersStr = sendGetRequest.requestGET(url);
        documentFiltersTable.add(url, filtersStr);
        FiltersDocumentItem[] filters = new FiltersDocumentItem[0];
        try {
            filters = RestClient.getGson().fromJson(filtersStr, FiltersDocumentItem[].class);
        } catch (Exception exc) {
            // handling error ...
        }
        if (filters != null) {
            for (FiltersDocumentItem filter : filters) {
                filter.setLevel(level);
                filtersList.add(filter);
                if (filter.getHasChildren().equals("true")) {
                    if (level == 1) {
                        if (filter.getFilterType() != null) {
                            getFilters(person.getHost() + "rest/api/docflow/doc/documents_filters?filterType=" +
                                    filter.getFilterType() + "&locale=" + MyApplication.getLang(), level + 1);
                        }
                    } else if (level == 2) {
                        if (filter.getObjectID() != null) {
                            getFilters(person.getHost() + "rest/api/docflow/doc/documents_filters?filterType=" +
                                    filter.getFilterType() + "&objectID=" + filter.getObjectID() + "&locale=" + MyApplication.getLang(), level + 1);
                        } else if (filter.getFilterID() != null) {
                            getFilters(person.getHost() + "rest/api/docflow/doc/documents_filters?filterType=" +
                                    filter.getFilterType() + "&filterID=" + filter.getFilterID() + "&locale=" + MyApplication.getLang(), level + 1);
                        } else {
                            getFilters(person.getHost() + "rest/api/docflow/doc/documents_filters?filterType=" +
                                    filter.getFilterType() + "&locale=" + MyApplication.getLang(), level + 1);
                        }
                    } else if (level >= 3) {
                        getFilters(person.getHost() + "rest/api/docflow/doc/documents_filters?filterType=" +
                                filter.getFilterType() + "&objectID=" + filter.getObjectID() + "&filterID=" + filter.getFilterID() + "&locale=" + MyApplication.getLang(), level + 1);
                    }
                }
            }
        }
    }

    /**
     * Метод загружает список документов для каждого фильтра, список работ, комментариев и т.д.
     */
    private void getDocuments() {
        for (FiltersDocumentItem filter : filtersList) {
            String result = "";
            String url = "";
            if (filter.getLevel() == 1) {
                if (filter.getFilterType() != null) {
                    url = person.getHost() + "rest/api/docflow/doc/documents?filterType=" +
                            filter.getFilterType() + "&pageNumber=0&locale=" + MyApplication.getLang();
                    result = sendGetRequest.requestGET(url);
                }
            } else if (filter.getLevel() == 2) {
                if (filter.getObjectID() != null) {
                    url = person.getHost() + "rest/api/docflow/doc/documents?filterType=" +
                            filter.getFilterType() + "&objectID=" + filter.getObjectID() + "&pageNumber=0&locale=" + MyApplication.getLang();
                    result = sendGetRequest.requestGET(url);
                } else if (filter.getFilterID() != null) {
                    url = person.getHost() + "rest/api/docflow/doc/documents?filterType=" +
                            filter.getFilterType() + "&filterID=" + filter.getFilterID() + "&pageNumber=0&locale=" + MyApplication.getLang();
                    result = sendGetRequest.requestGET(url);
                } else {
                    url = person.getHost() + "rest/api/docflow/doc/documents?filterType=" +
                            filter.getFilterType() + "&pageNumber=0&locale=" + MyApplication.getLang();
                    result = sendGetRequest.requestGET(url);
                }
            } else if (filter.getLevel() >= 3) {
                url = person.getHost() + "rest/api/docflow/doc/documents?filterType=" + filter.getFilterType() +
                        "&objectID=" + filter.getObjectID() + "&filterID=" + filter.getFilterID() + "&pageNumber=0&locale=" + MyApplication.getLang();
                result = sendGetRequest.requestGET(url);
            }
            documentsTable.add(url, result);
            List<DocumentItem> documents = RestClient.getGson().fromJson(result, new TypeToken<List<DocumentItem>>() {}.getType());
            for (DocumentItem document : documents) {

                offlineLogs.add("1", "Документ " + "\"" + document.getName() + "\"" + " успешно синхронизирован",
                        sdf.format(System.currentTimeMillis()), random + "");

                getComments(document);
                getAttachments(document);
            }
        }
    }

    /**
     * Метод используется для загрузки комментариев для документа
     *
     * @param document информация о документе
     */
    private void getComments(DocumentItem document) {
        if (document.getActions() == null || document.getActions().length == 0) {
            String url = person.getHost() + "rest/api/docflow/doc/comments/list?documentID=" +
                    document.getDocumentID() + "&count=999&locale=" + MyApplication.getLang();
            String comments = sendGetRequest.requestGET(url);
            List<CommentItem> commentList = RestClient.getGson().fromJson(comments, new TypeToken<List<CommentItem>>() {
            }.getType());
            for (CommentItem comment : commentList) {
                documentCommentsTable.add(document.getDocumentID(), comment.getComment(), comment.getAuthor().getName(),
                        comment.getCreated_label(), comment.getComment_icon_type(), comment.getCommentID());
            }
        }
    }

    /**
     * Метод используется для загрузки вложений для документач
     *
     * @param document документ
     */
    private void getAttachments(DocumentItem document) {
        String url = person.getHost() + "rest/api/docflow/doc/attachments?documentID=" +
                document.getDocumentID() + "&locale=" + MyApplication.getLang();
        String attachments = sendGetRequest.requestGET(url);
        documentAttachmentsTable.add(document.getDocumentID(), attachments);
    }

    /**
     * Получение комментариев для работы
     *
     * @param workID идентификатор работы
     */
    private void getCommentsForWork(String workID) throws Exception {

        WorkItem work = new WorkItem();
        work.setActionID(workID);

        // комментарии к работе
        String commentsStr = sendGetRequest.requestGET(person.getHost() + "rest/api/workflow/work/" +
                work.getActionID() + "/comments?count=999" + "&locale=" + MyApplication.getLang() + "&type=" + CommentConst.WORK);
        comments.add(commentsStr, CommentConst.WORK, workID);

        // комментарии к документу
        commentsStr = sendGetRequest.requestGET(person.getHost() + "rest/api/workflow/work/" +
                work.getActionID() + "/comments?count=999" + "&locale=" + MyApplication.getLang() + "&type=" + CommentConst.DOCUMENT);
        comments.add(commentsStr, CommentConst.DOCUMENT, workID);

        // личные
        commentsStr = sendGetRequest.requestGET(person.getHost() + "rest/api/workflow/work/" +
                work.getActionID() + "/comments?count=999" + "&locale=" + MyApplication.getLang() + "&type=" + CommentConst.PERSONAL);
        comments.add(commentsStr, CommentConst.PERSONAL, workID);
    }

    /**
     * Получение действий для работы
     *
     * @param workID идентификатор работы
     */
    private void getActionsForWork(String workID) throws Exception {

        WorkItem work = new WorkItem();
        work.setActionID(workID);

        // действия с работой
        String actionsStr = sendGetRequest.requestGET(person.getHost() + "rest/api/workflow/work_actions?workID=" +
                work.getActionID() + "&locale=" + MyApplication.getLang());
        actions.add(actionsStr, workID);
    }

    /**
     * Получения форм завершения для работы
     *
     * @param workID идентификатор работы
     */
    private void getFormCompletion(String workID) throws Exception {
        String formType = sendGetRequest.requestGET(person.getHost() + "rest/api/workflow/work/get_completion_data?workID=" +
                workID + "&locale=" + MyApplication.getLang());
        CompletionFormItem completionFormItem = RestClient.getGson().fromJson(formType, CompletionFormItem.class);
        if (completionFormItem.getErrorCode() == null) {
            formsCompletion.addFormType(completionFormItem, workID);
        }
    }

    public void setDocumentsTable(DocumentTable documentsTable) {
        this.documentsTable = documentsTable;
    }

    public void setSendGetRequest(SendGetRequest sendGetRequest) {
        this.sendGetRequest = sendGetRequest;
    }
}