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

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.view.View;
import android.widget.Toast;

import com.devspark.appmsg.AppMsg;
import com.pnikosis.materialishprogress.ProgressWheel;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import kz.arta.synergy.workflow.mobile.android.R;
import kz.arta.synergy.workflow.mobile.android.common.models.ErrorCode;
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.MyApplication;
import kz.arta.synergy.workflow.mobile.android.common.utils.Wrapper;
import kz.arta.synergy.workflow.mobile.android.documents.common.activities.DocumentInfoActivity;
import kz.arta.synergy.workflow.mobile.android.documents.common.models.DocumentItem;
import kz.arta.synergy.workflow.mobile.android.documents.route.activities.RouteActivity;
import kz.arta.synergy.workflow.mobile.android.documents.route.models.Route;
import kz.arta.synergy.workflow.mobile.android.documents.route.models.RouteItem;
import kz.arta.synergy.workflow.mobile.android.documents.route.models.RouteItemUser;
import kz.arta.synergy.workflow.mobile.android.documents.route.models.Routes;

/**
 * Created by neox on 24.07.15.
 * Класс для работы с реестрами
 */
public class RouteManager {

    /**
     * Данные пользователя
     */
    private Person person;

    /**
     * Активити, из которого запускается класс
     */
    private Activity activity;

    /**
     * Документ
     */
    private DocumentItem document;

    /**
     * Маршруты
     */
    private Routes routes;

    /**
     * Тип события
     *
     * @see RoutesConst#ACTIVATE
     * @see RoutesConst#CHANGE
     */
    private String type;

    public RouteManager(Routes routes, DocumentItem document, Person person, Activity activity, String type) {
        this.routes = routes;
        this.person = person;
        this.activity = activity;
        this.document = document;
        this.type = type;
    }

    /**
     * Открывать ли экран со списком маршутов, либо сразу запускать
     *
     * @return true/false
     */
    public boolean isShowActivity() {
        return !(!routes.getBefore().getShowOnSave().equals("true") &&
                !routes.getAction().getShowOnSave().equals("true") &&
                !routes.getAfter().getShowOnSave().equals("true"));
    }

    /**
     * Метод используется для запуска маршрута
     */
    public void startRoute(final ProgressWheel progressBar) {
        if (document == null || routes == null) {
            return;
        }
        new AsyncTask<Void, Void, String>() {
            @Override
            protected void onPreExecute() {
                progressBar.setVisibility(View.VISIBLE);
                super.onPreExecute();
            }

            @Override
            protected void onPostExecute(String result) {
                progressBar.setVisibility(View.GONE);
                if (result == null) {
                    AppMsg.makeText(activity, activity.getString(R.string.error_to_start_route), AppMsg.STYLE_ALERT).show();
                    return;
                }
                try {
                    ErrorCode errorCode = RestClient.getGson().fromJson(result, ErrorCode.class);
                    if (errorCode.getErrorCode().equals(Wrapper.ERROR)) {
                        AppMsg.makeText(activity, errorCode.getErrorMessage(), AppMsg.STYLE_ALERT).show();
                    }
                } catch (Exception exc) {
                    Result uuid = RestClient.getGson().fromJson(result, Result.class);
                    if (uuid.uuid == null) {
                        AppMsg.makeText(activity, activity.getString(R.string.error_to_start_route), AppMsg.STYLE_ALERT).show();
                        return;
                    }
                    // если маршрут запускается из экрана информации о документе
                    if (activity instanceof DocumentInfoActivity) {
                        if (routes.getCloseAfterActivation().equals("true")) {
                            activity.finish();
                        } else {
                            ((DocumentInfoActivity) activity).update();
                        }
                    } else if (activity instanceof RouteActivity) {
                        Intent intent = new Intent();
                        intent.putExtra(RoutesConst.CLOSE_DOCUMENT, (routes.getCloseAfterActivation().equals("true")));
                        activity.setResult(Activity.RESULT_OK, intent);
                        activity.finish();
                        Toast.makeText(activity, activity.getString(R.string.data_saved), Toast.LENGTH_LONG).show();
                    }
                }
                super.onPostExecute(result);
            }

            @Override
            protected String doInBackground(Void... params) {
                return start();
            }
        }.execute();
    }

    /**
     * Метод используется для запуска маршрута (запрос на сервер)
     *
     * @return идентификатор созданного дерева процессов
     */
    public String start() {
        try {
            HttpURLConnection conn = SendGetRequest.getConnection(person,
                    "rest/api/registry/route/start?locale=" + MyApplication.getLang());
            if (conn == null) {
                return null;
            }
            DataOutputStream request = new DataOutputStream(conn.getOutputStream());
            request.writeBytes("documentID=" + URLEncoder.encode(document.getDocumentID(), "utf-8") + "&");
            request.writeBytes("dataUUID=" + URLEncoder.encode(document.getAsfDataID(), "utf-8") + "&");
            request.writeBytes("subject=" + URLEncoder.encode(document.getFormName(), "utf-8") + "&");
            request.writeBytes("registryID=" + URLEncoder.encode(document.getRegistryID(), "utf-8") + "&");
            request.writeBytes("type=" + URLEncoder.encode(type, "utf-8") + "&");
            request.writeBytes("data=" + URLEncoder.encode(getData(), "utf-8") + "&");
            request.flush();
            request.close();
            InputStream is = conn.getInputStream();
            BufferedReader rd = new BufferedReader(new InputStreamReader(is));
            String line;
            StringBuilder response = new StringBuilder();
            while ((line = rd.readLine()) != null) {
                response.append(line);
                response.append('\r');
            }
            rd.close();
            return response.toString();
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    /**
     * Метод проверяет валидная ли строка 'data'
     *
     * @return true/false
     */
    public boolean isValid() {
        return isValidRoute(routes.getBefore()) && isValidRoute(routes.getAfter());
    }

    /**
     * Метод проверяет заполнены ли ответственные в нужных этапах
     *
     * @param route маршрут
     * @return true - все нормально, иначе - false
     */
    private boolean isValidRoute(Route route) {
        for (RouteItem item : route.getItems()) {
            for (RouteItemUser user : item.getUsers()) {
                if (user.getTypeID().equals(RoutesConst.Processes.ASSIGNMENT) || user.getTypeID().equals(RoutesConst.Processes.AGREEMENT) ||
                        user.getTypeID().equals(RoutesConst.Processes.APPROVAL) || user.getTypeID().equals(RoutesConst.Processes.ACQUAINTANCE) ||
                        user.getTypeID().equals(RoutesConst.Processes.RESOLUTION)) {
                    if (user.getUserID().isEmpty()) {
                        AppMsg.makeText(activity, activity.getString(R.string.need_route_item_user), AppMsg.STYLE_ALERT).show();
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * Метод возващает строку data - описание маршрутов (для отправки на сервер)
     *
     * @return data
     */
    private String getData() {
        String before = getRouteJson(routes.getBefore());
        String after = getRouteJson(routes.getAfter());
        return "{" + "\"before\":" + before + "," + "\"after\":" + after + "}";
    }

    /**
     * Метод возвращает json описание текущего маршрута
     *
     * @param route маршрут
     * @return json строка
     */
    private String getRouteJson(Route route) {
        List<JsonRouteItem> routeItems = new ArrayList<>();
        for (RouteItem routeItem : route.getItems()) {
            List<JsonRouteItemUser> users = new ArrayList<>();
            for (RouteItemUser routeItemUser : routeItem.getUsers()) {
                JsonRouteItemUser user = new JsonRouteItemUser();
                user.name = routeItemUser.getName();
                user.itemID = routeItemUser.getItemID();
                user.typeID = routeItemUser.getTypeID();
                user.userID = routeItemUser.getUserID();
                user.lengthType = routeItemUser.getLengthType();
                user.length = routeItemUser.getLength();
                user.workLoadType = routeItemUser.getWorkLoadType();
                user.workloadValue = routeItemUser.getWorkloadValue();
                user.returnNumber = routeItemUser.getReturnNumber();
                user.completionFormID = routeItemUser.getCompletionFormID();
                if (user.typeID.equals(RoutesConst.Processes.ROUTE)) {
                    user.routeID = routeItemUser.getRouteID();
                }
                users.add(user);
            }
            JsonRouteItem item = new JsonRouteItem();
            item.code = routeItem.getCode();
            item.itemID = routeItem.getCode();
            item.users = users;
            routeItems.add(item);
        }
        JsonRoute r = new JsonRoute();
//        r.routeID = routes.getBefore().getRouteID();
        r.items = routeItems;
        return RestClient.getGson().toJson(r);
    }

    /**
     * Подэтап маршрута
     */
    class JsonRouteItemUser {

        /**
         * Имя
         */
        String name;

        /**
         * Идентификатор пункта
         */
        String itemID;

        /**
         * Идентификатор процесса
         */
        String typeID;

        /**
         * Идентификатор пользователя
         */
        String userID;

        /**
         * Тип длительности
         */
        String lengthType;

        /**
         * Длительность
         */
        String length;

        /**
         * Тип нагрузки
         */
        String workLoadType;

        /**
         * Нагрузка
         */
        String workloadValue;

        /**
         * Номер возврата
         */
        String returnNumber;

        /**
         * Идентификатор формы завершения
         */
        String completionFormID;

        /**
         * Идентификатор маршрута
         */
        String routeID;
    }

    /**
     * Этап маршрута
     */
    class JsonRouteItem {

        /**
         * Код этапа
         */
        String code;

        /**
         * Идентификатор этапа
         */
        String itemID;

        /**
         * Список этапов
         */
        List<JsonRouteItemUser> users;
    }

    /**
     * Маршрут
     */
    class JsonRoute {

        /**
         * Идентификатор маршрута
         */
        String routeID;

        /**
         * Этапы маршрута
         */
        List<JsonRouteItem> items;
    }

    /**
     * Результат выполнения метода
     */
    class Result {

        /**
         * Идентификатор созданного процесса
         */
        String uuid;
    }
}
