package com.tofly.ghrq_route.module.plan;

import android.content.Context;
import android.location.Location;

import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.Polygon;
import com.esri.arcgisruntime.geometry.SpatialReference;
import com.mgq.base.utils.progressdialog.ProgressManager;
import com.mgq.base.utils.toast.ToastUtil;
import com.tofly.ghrq_route.R;
import com.tofly.ghrq_route.base.BaseApp;
import com.tofly.ghrq_route.base.C;
import com.tofly.ghrq_route.module.OfflineWork.domain.OfflineWorkJobBean;
import com.tofly.ghrq_route.module.deviceInfo.DeviceInfoTool;
import com.tofly.ghrq_route.module.gps.GpsTool;
import com.tofly.ghrq_route.module.plan.controller.PlanCallBack;
import com.tofly.ghrq_route.module.plan.controller.PlanController;
import com.tofly.ghrq_route.module.plan.domain.OfflinePathBean;
import com.tofly.ghrq_route.module.plan.domain.PlanBean;
import com.tofly.ghrq_route.module.sign.domain.SignDataBean;
import com.tofly.ghrq_route.module.sqlite.DBDaoHelper;
import com.tofly.ghrq_route.module.trouble.TroubleTool;
import com.tofly.ghrq_route.module.trouble.domain.TroubleBean;
import com.tofly.ghrq_route.module.user.domain.UserBean;
import com.tofly.ghrq_route.common.util.ArcgisUtils.ArcgisUtils;
import com.tofly.ghrq_route.common.util.date.DateUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Created by Amu on 2017/4/26.
 */

public class PlanTool {

    private static final String TAG = PlanTool.class.getName();

    private static PlanTool planTool = null;

    private PlanController planController;

    private DBDaoHelper dbDaoHelper;

    private PlanTool(){
        dbDaoHelper = DBDaoHelper.getInstance();
    }

    public static synchronized PlanTool getInstance(){
        if (planTool == null){
            planTool = new PlanTool();
        }
        return planTool;
    }

    public TroubleBean getLocalTrouble(String trouble_id){
        TroubleTool troubleTool = TroubleTool.getInstance();
        return troubleTool.getLocalTrouble(trouble_id);
    }

    private void getPlanListMobile(final Context context, int plan_state, int period, int plan_mode, boolean online, final PlanCallBack planCallBack) {
        final int pageindex = 1;
        final int pagesize = C.DEFAULT_MAX_LOAD_PAGESIZE;
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            if (planController == null)
                planController = new PlanController(context);
            planController.getPlanListMobile(context, userBean.getUserid(),
                    plan_state, period, plan_mode, pageindex, pagesize, online, new PlanCallBack(){
                @Override
                public void onGetPlanList(boolean isSuccess, int errorCode, String errMsg, List<PlanBean> planList, int total) {
                    super.onGetPlanList(isSuccess, errorCode, errMsg, planList, total);
                    if (isSuccess){
                    }else {
                        errMsg = BaseApp.formatErrorMessage(errorCode, errMsg);
                        String strWarn = context.getString(R.string.plan_get_plan_list_error) + errMsg;
                        ToastUtil.showToast(context, strWarn);
                    }

                    if (planCallBack != null)
                        planCallBack.onGetPlanList(isSuccess, errorCode, errMsg, planList, total);
                }
            });
        }
    }

    private void getPlanList(final Context context, int plan_state, int period, int plan_mode, boolean online, final PlanCallBack planCallBack) {
        final int pageindex = 1;
        final int pagesize = C.DEFAULT_MAX_LOAD_PAGESIZE;
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            if (planController == null)
                planController = new PlanController(context);
            planController.getPlanList(userBean.getToken(), userBean.getUserid(),
                    plan_state, period, plan_mode, pageindex, pagesize, online, new PlanCallBack(){
                        @Override
                        public void onGetPlanList(boolean isSuccess, int errorCode, String errMsg, List<PlanBean> planList, int total) {
                            super.onGetPlanList(isSuccess, errorCode, errMsg, planList, total);
                            if (isSuccess){
                            }else {
                                errMsg = BaseApp.formatErrorMessage(errorCode, errMsg);
                                String strWarn = context.getString(R.string.plan_get_plan_list_error) + errMsg;
                                ToastUtil.showToast(context, strWarn);
                            }

                            if (planCallBack != null)
                                planCallBack.onGetPlanList(isSuccess, errorCode, errMsg, planList, total);
                        }
                    });
        }
    }

    public void getPlanUnStartedList(Context context, PlanCallBack planCallBack){
        int plan_mode = BaseApp.getInstance().isCarMode() ? 1 : 0;
        int period = -1;
        getPlanList(context, PlanBean.SELECT_STATE_UNSTARTED, period, plan_mode, true, planCallBack);
    }

    public void getPlanTransferableList(Context context, PlanCallBack planCallBack){
        int plan_mode = BaseApp.getInstance().isCarMode() ? 1 : 0;
        int period = 1;
        getPlanListMobile(context, PlanBean.SELECT_STATE_UNSTARTED, period, plan_mode, true, planCallBack);
    }

    public void getPlanListToday(Context context, PlanCallBack planCallBack){
        int plan_mode = BaseApp.getInstance().isCarMode() ? 1 : 0;
        getPlanListMobile(context, PlanBean.SELECT_STATE_TODAY, -1, plan_mode, true, planCallBack);
    }

    public void getPlanListTodayOffline(final Context context, int plan_state, PlanCallBack planCallBack){
        int plan_mode = BaseApp.getInstance().isCarMode() ? 1 :0;
        getPlanListMobile(context, plan_state, -1, plan_mode, false, planCallBack);
    }

    public void transferPlan(final Context context, List<String> plan_ids, String note, final PlanCallBack planCallBack){
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null){
            if (plan_ids != null && plan_ids.size() > 0){
                if (planController == null)
                    planController = new PlanController(context);
                planController.transferPlanApply(context, plan_ids, note, new PlanCallBack(){
                    @Override
                    public void onTransferPlanApply(boolean isSuccess, int errorCode, String errMsg) {
                        super.onTransferPlanApply(isSuccess, errorCode, errMsg);
                        if (isSuccess){
                        }else {
                            errMsg = BaseApp.formatErrorMessage(errorCode, errMsg);
                            ToastUtil.showToast(context, errMsg);
                        }

                        if (planCallBack != null)
                            planCallBack.onTransferPlanApply(isSuccess, errorCode, errMsg);
                    }
                });
            }
        }
    }

    public void getPlanInfo(final Context context, String plan_id, boolean online, final PlanCallBack planCallBack) {
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            if (planController == null)
                planController = new PlanController(context);
            planController.getPlanInfo(userBean.getToken(), plan_id, online, new PlanCallBack(){
                @Override
                public void onGetPlanInfo(boolean isSuccess, int errorCode, String errMsg, PlanBean plan) {
                    super.onGetPlanInfo(isSuccess, errorCode, errMsg, plan);
                    if (planCallBack != null)
                        planCallBack.onGetPlanInfo(isSuccess, errorCode, errMsg, plan);
                }
            });
        }
    }

    public void getOnlinePlanInfo(Context context, String plan_id, PlanCallBack planCallBack){
        getPlanInfo(context, plan_id, true, planCallBack);
    }

    public void getLocalPlanInfo(Context context, String plan_id, PlanCallBack planCallBack){
        getPlanInfo(context, plan_id, false, planCallBack);
    }

    public PlanBean getLocalPlan(String plan_id){
        return dbDaoHelper.getPlan(plan_id);
    }

    public List<PlanBean> getLocalPlans(){
        List<PlanBean> localPlans = null;
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            int plan_mode = BaseApp.getInstance().isCarMode() ? 1 :0;
            localPlans = dbDaoHelper.getPlanList(userBean.getUserid(), plan_mode);
        }
        return localPlans;
    }

    public List<PlanBean> getLocalPlans(int device_type_id){
        List<PlanBean> localPlans = null;
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            int plan_mode = BaseApp.getInstance().isCarMode() ? 1 :0;
            localPlans = dbDaoHelper.getPlanListByDeviceType(userBean.getUserid(), plan_mode, device_type_id);
        }
        return localPlans;
    }

    public List<PlanBean> getLocalDevicePlans(){
        List<PlanBean> localPlans = null;
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            int plan_mode = BaseApp.getInstance().isCarMode() ? 1 :0;
            List<Integer> deviceTypes = PlanBean.getDeviceTypes();
            localPlans = dbDaoHelper.getPlanListByDeviceType(userBean.getUserid(), plan_mode, deviceTypes);
        }
        return localPlans;
    }

    public List<String> getLocalPlanIds(){
        List<String> localPlanIds = null;
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            int plan_mode = BaseApp.getInstance().isCarMode() ? 1 :0;
            localPlanIds = dbDaoHelper.getLocalPlanIds(userBean.getUserid(), plan_mode);
        }
        return localPlanIds;
    }

    public void updatePlanRecalculateState(final Context context, String plan_id, final PlanCallBack planCallBack){
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            if (planController == null)
                planController = new PlanController(context);
            planController.getRecalculatePlanPoints(userBean.getToken(), plan_id, new PlanCallBack() {
                @Override
                public void onGetRecalculatePlanPoints(boolean isSuccess, int errorCode, String errMsg, List<String> pointIds) {
                    super.onGetRecalculatePlanPoints(isSuccess, errorCode, errMsg, pointIds);
                    ProgressManager.getInstance().cancelProgress();
                    if (isSuccess) {
                    } else {
                        errMsg = BaseApp.formatErrorMessage(errorCode, errMsg);
                        ToastUtil.showToast(context, errMsg);
                    }
                    if (planCallBack != null)
                        planCallBack.onGetRecalculatePlanPoints(isSuccess, errorCode, errMsg, pointIds);
                }
            });
        }
    }

    public void updateServerRecalculateState(final Context context, String plan_id, final PlanCallBack planCallBack){
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null) {
            if (planController == null)
                planController = new PlanController(context);
            planController.updateRecalculatePlanState(userBean.getToken(), plan_id, new PlanCallBack() {
                @Override
                public void onUpdateRecalculatePlanState(boolean isSuccess, int errorCode, String errMsg) {
                    super.onUpdateRecalculatePlanState(isSuccess, errorCode, errMsg);
                    ProgressManager.getInstance().cancelProgress();
                    if (isSuccess) {
                    } else {
                        errMsg = BaseApp.formatErrorMessage(errorCode, errMsg);
                        ToastUtil.showToast(context, errMsg);
                    }
                    if (planCallBack != null)
                        planCallBack.onUpdateRecalculatePlanState(isSuccess, errorCode, errMsg);
                }
            });
        }
    }

    public void checkLocalPlanIsOver(){
        List<PlanBean> planBeans = getLocalPlans();
        if (planBeans != null){
            for (PlanBean planBean : planBeans){
                setPlanIsOver(planBean.getPlan_id());
            }
        }
    }

    public PlanBean setPlanIsOver(String plan_id) {
        PlanBean planBean = dbDaoHelper.getPlan(plan_id);
        boolean isPlanOver = dbDaoHelper.isPlanOver(plan_id);
        if (planBean != null) {
            if (isPlanOver) {
                planBean.setPlan_state(PlanBean.PlAN_STATE_TYPE.PLAN_STATE_OVER);
                planBean.setPercent2("1");
                planBean.setPlan_process_name("计划结束");
                planBean.setPlan_overdate(DateUtils.getDate());
                dbDaoHelper.insertOrUpdatePlan(planBean);
            }else {
                long over_count = dbDaoHelper.getPlanOverCount(plan_id);
                int total_count = planBean.getPoint_num();
                float percent1 = 0;
                if (total_count > 0)
                    percent1 = (float) Math.round(over_count * 100 / total_count) / 100;
                String strPercent = String.valueOf(percent1);
                planBean.setPercent2(strPercent);
                dbDaoHelper.insertOrUpdatePlan(planBean);
            }
        }
        return planBean;
    }

    public void addPlanOfflineJob(String plan_id){
        if (true)
            return;

        OfflineWorkJobBean workJobBean = dbDaoHelper.getOfflineWorkJob(OfflineWorkJobBean.OfflineWorkJobType.JOB_PLAN_INFO_CHANGED);
        List<String> plan_ids;
        if (workJobBean == null){
            workJobBean = new OfflineWorkJobBean();
            workJobBean.setId(UUID.randomUUID().toString());
            UserBean userBean = BaseApp.getInstance().getLoginUser();
            workJobBean.setUser_id(userBean.getUserid());
            workJobBean.setJob_type(OfflineWorkJobBean.OfflineWorkJobType.JOB_PLAN_INFO_CHANGED);
            plan_ids = new ArrayList<>();
        }else {
            plan_ids = workJobBean.getRef_data_ids();
            if (plan_ids == null)
                plan_ids = new ArrayList<>();
            else {
                if (!plan_ids.contains(plan_id))
                    plan_ids.add(plan_id);
            }
        }
        workJobBean.setRef_data_ids(plan_ids);
        dbDaoHelper.insertOfflineWorkJob(workJobBean);
    }

    public void getPlanPointsOnline(final Context context, String plan_id, final PlanCallBack planCallBack) {
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null && plan_id != null) {
            if (planController == null)
                planController = new PlanController(context);
            planController.getChildPlanPointList(userBean.getToken(), plan_id, 1, 1000, new PlanCallBack() {
                @Override
                public void onGetChildPlanPointList(boolean isSuccess, int errorCode, String errMsg, List<OfflinePathBean> planPointList) {
                    super.onGetChildPlanPointList(isSuccess, errorCode, errMsg, planPointList);
                    ProgressManager.getInstance().cancelProgress();
                    if (isSuccess) {
                    }else {
                        errMsg = BaseApp.formatErrorMessage(errorCode, errMsg);
                        ToastUtil.showToast(context, errMsg);
                    }
                    if (planCallBack != null)
                        planCallBack.onGetChildPlanPointList(isSuccess, errorCode, errMsg, planPointList);
                }
            });
        }
    }

    public boolean isNeedUpdatePlan(){
        boolean isNeedUpdate = false;
        SignDataBean onSign = dbDaoHelper.getTodaySignOn();
        UserBean user = BaseApp.getInstance().getLoginUser();
        if (onSign != null && user != null){
            int car_mode = user.getCar_mode();
            int needUpdate = (car_mode == UserBean.PATROL_TYPE_CAR ? onSign.getCarNeedUpdate() : onSign.getNeedUpdate());
            if (needUpdate == 1){
                isNeedUpdate = true;
            }
        }
        return isNeedUpdate;
    }

    public boolean isUpdatingPlan(){
        boolean isUpdating = false;
        SignDataBean onSign = dbDaoHelper.getTodaySignOn();
        if (onSign != null){
            isUpdating = onSign.getPlanState() == 2;
        }
        return isUpdating;
    }

    public void needTodayPlanPoint(){
        SignDataBean signOnData = getTodaySignOn();
        if (signOnData != null) {
            signOnData.setPlanState(0);
            dbDaoHelper.insertOrUpdateSignOn(signOnData);
        }
        DeviceInfoTool.getInstance().checkTodayPlan();
    }

    public void resetTodayPlan() {
        SignDataBean signOnData = getTodaySignOn();
        if (signOnData != null) {
            signOnData.setPlanState(0);
            dbDaoHelper.insertOrUpdateSignOn(signOnData);
        }
    }

    public void needCurrentPlanPoint(String plan_id){
        SignDataBean signOnData = dbDaoHelper.getTodaySignOn();
        if (signOnData != null){
            signOnData.setPlanIds(plan_id);
            signOnData.setPlanState(0);
            dbDaoHelper.insertOrUpdateSignOn(signOnData);
            DeviceInfoTool.getInstance().checkTodayPlan();
        }
    }

    public SignDataBean getTodaySignOn(){
        return dbDaoHelper.getTodaySignOn();
    }

    /*获取本地所有该计划的离线点数据*/
    public List<OfflinePathBean> getLocalPlanPoints(String plan_id){
        return dbDaoHelper.getPlanOfflinePathList(plan_id);
    }

    /*获取本地所有该计划的离线点数据*/
    public Map<String, List<OfflinePathBean>> getLocalPlanPointsOrderByPath(String plan_id){
        Map<String, List<OfflinePathBean>> pathMap = new HashMap<>();
        List<OfflinePathBean> pathBeans = dbDaoHelper.getPlanOfflinePathListOrderByPathId(plan_id);
        for (OfflinePathBean pathBean : pathBeans) {
            String path_id = pathBean.getPath_id();
            if (pathMap.containsKey(path_id)) {
                List<OfflinePathBean> points = pathMap.get(path_id);
                points.add(pathBean);
            }else {
                List<OfflinePathBean> points = new ArrayList<>();
                points.add(pathBean);
                pathMap.put(path_id, points);
            }
        }
        return pathMap;
    }

    /*获取本地所有该计划已到位的离线点数据*/
    public Map<String, List<OfflinePathBean>> getLocalOverPlanPointsOrderByPath(String plan_id){
        Map<String, List<OfflinePathBean>> pathMap = new HashMap<>();
        List<OfflinePathBean> pathBeans = dbDaoHelper.getPlanOfflinePathOverListOrderByPathId(plan_id);
        for (OfflinePathBean pathBean : pathBeans) {
            String path_id = pathBean.getPath_id();
            if (pathMap.containsKey(path_id)) {
                List<OfflinePathBean> points = pathMap.get(path_id);
                points.add(pathBean);
            }else {
                List<OfflinePathBean> points = new ArrayList<>();
                points.add(pathBean);
                pathMap.put(path_id, points);
            }
        }
        return pathMap;
    }

    private static final int RENDER_REGION = 100;  //200米范围内的数据
    /*获取本地该计划的离线点数据--在范围内*/
    public Map<String, List<OfflinePathBean>> getLocalPlanPointsInRegion(Point location, SpatialReference sp, String plan_id){
        if (location == null || sp == null)
            return null;

        Map<String, List<OfflinePathBean>> pathMap = new HashMap<>();
        List<OfflinePathBean> pointList = null;
        Polygon polygon = ArcgisUtils.getLocationCircleGeometry(location, RENDER_REGION, sp);
        if (polygon != null) {
            Envelope extent = polygon.getExtent();
            pointList = dbDaoHelper.getPlanOfflinePathListInRegion(plan_id, extent.getXMin(), extent.getXMax(), extent.getYMin(), extent.getYMax());
        }
        if (pointList != null) {
            for (OfflinePathBean pathBean : pointList) {
                String path_id = pathBean.getPath_id();
                if (pathMap.containsKey(path_id)) {
                    List<OfflinePathBean> points = pathMap.get(path_id);
                    points.add(pathBean);
                } else {
                    List<OfflinePathBean> points = new ArrayList<>();
                    points.add(pathBean);
                    pathMap.put(path_id, points);
                }
            }
        }
        return pathMap;
    }

    public List<String> getLocalPlanPlanPathsInRegion(Point location, SpatialReference sp, String plan_id){
        List<String> pathIds = null;
        Polygon polygon = ArcgisUtils.getLocationCircleGeometry(location, RENDER_REGION, sp);
        if (polygon != null) {
            Envelope extent = polygon.getExtent();
            pathIds = dbDaoHelper.getPlanOfflinePathIdInRegion(plan_id, extent.getXMin(), extent.getXMax(), extent.getYMin(), extent.getYMax());
        }
        return pathIds;
    }

    public long getLocalPlanPointCount(String plan_id) {
        return dbDaoHelper.getOfflinePathPlanCounts(plan_id);
    }

    public List<String> getLocalPlanPlanPaths(String plan_id){
        return dbDaoHelper.getPlanOfflinePathId(plan_id);
    }

    public List<OfflinePathBean> getLocalPlanPathPoints(String plan_id, String path_id){
        return dbDaoHelper.getPlanOfflinePathList(plan_id, path_id);
    }

    /*获取本地某个巡检线计划的path_id获取组成该段线的点*/
    public List<OfflinePathBean> getLocalPathPlanPoints(String path_id){
        UserBean userBean = BaseApp.getInstance().getLoginUser();
        if (userBean != null){
            return dbDaoHelper.getPathListByPathId(userBean.getUserid(), path_id);
        }
        return null;
    }

    public OfflinePathBean getLocalPlanPoint(String temp_id){
        return dbDaoHelper.getPlanOfflinePath(temp_id);
    }

    public OfflinePathBean getLocalPlanPointByRFID(String plan_id, String rfid){
        return dbDaoHelper.getOfflinePathByRfid(plan_id, rfid);
    }

    public long getOfflinePathPlanCounts(String plan_id){
        return dbDaoHelper.getOfflinePathPlanCounts(plan_id);
    }

    public long getOfflinePathPlanCounts(String plan_id, int pageindex){
        return dbDaoHelper.getOfflinePathPlanCounts(plan_id, pageindex);
    }

    public void updateLocalPointOver(List<String> pointIds){
        if (pointIds != null && pointIds.size() > 0){
            dbDaoHelper.updateLocalPointsFromServerOver(pointIds);
        }
    }

    public boolean checkPlanDeviceInPlace(Point point, OfflinePathBean pathBean){
        boolean isover = false;
        if (point != null && point.getX() > 0 && point.getY() > 0) {
            double lng = point.getX();
            double lat = point.getY();
            if (pathBean != null) {
                double x = pathBean.getLng();
                double y = pathBean.getLat();
                if (x > 0 && y > 0){
                    double tolerance = -1;
                    String plan_id = pathBean.getPlan_id();
                    PlanBean planBean = planTool.getLocalPlan(plan_id);
                    if (planBean != null) {
                        tolerance = planBean.getTolerance();
                    }
                    isover = GpsTool.checkRouteDevicePointOver(x, y, lng, lat, tolerance);
                }
            }
        }
        return isover;
    }

    public boolean checkPlanValid(Context context, OfflinePathBean planPoint, Point location, PlanBean planBean) {
        boolean isOutDate;
        boolean is_finished;
        boolean isOver;

        is_finished = planPoint.getState() == OfflinePathBean.POINT_STATE_FINISHED;
        if (is_finished)
            return false;

        isOutDate = isOutOfDate(planBean);
        if (isOutDate) {
            ToastUtil.showToast(context, "当前巡检点时间未到或者已超过最后期限。");
            return false;
        }

        Point curLocation = location;
        Location lastLoc = GpsTool.getInstance().getLocationInfo();
        if (lastLoc != null){
            curLocation = ArcgisUtils.projectLocationDefault(lastLoc.getLongitude(), lastLoc.getLatitude());
        }

        if (false) {
            isOver = checkPlanDeviceInPlace(curLocation, planPoint);
            if (!isOver) {
                ToastUtil.showToast(context, "未达到巡检设备附近位置，不能进行录入操作！");
                return false;
            }
        }

        return true;
    }

    public boolean isOutOfDate(PlanBean planBean) {
        boolean isOutOfDate = false;
        if (planBean != null) {
            isOutOfDate = planBean.isOutOfDate();
        }
        return isOutOfDate;
    }

    /*清除当前用户所有的本地离线点数据*/
    public void clearAllLocalOfflinePath(String userid, int carmode){
        dbDaoHelper.clearAllLocalOfflinePath(userid, carmode);
    }

}
