package com.atmob.map_amap_android.overlays.polyline;

import android.content.Context;
import android.graphics.Color;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdate;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.atmob.map_amap_android.R;
import com.atmob.map_amap_android.bean.MapPadding;
import com.atmob.map_amap_android.contants.Constants;
import com.atmob.map_amap_android.overlays.MyMethodCallHandler;
import com.atmob.map_amap_android.util.GsonUtil;
import com.atmob.map_amap_android.util.LogUtil;
import com.atmob.map_amap_android.util.ParamUtil;
import com.atmob.map_amap_android.util.SizeUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public class PolylineController implements MyMethodCallHandler {


    private final String TAG = "PolylineController";

    private final AMap map;

    private final Context context;

    private final HashMap<String, Polyline> currentPolylineMap = new HashMap<>(10);

    private final MethodChannel methodChannel;
    private final Gson gson;

    public PolylineController(Context context, MethodChannel methodChannel, AMap map) {
        this.context = context;
        this.methodChannel = methodChannel;
        this.map = map;
        gson = GsonUtil.getInstance();
    }

    @Override
    public void doMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        LogUtil.i(TAG, "doMethodCall===>" + call.method + "  arguments===>" + call.arguments);
        switch (call.method) {
            case Constants.METHOD_UPDATE_OR_ADD_POLYLINE:
                addPolyline(call, result);
                break;
            case Constants.METHOD_REMOVE_POLYLINE:
                removePolyLine(call, result);
                break;
            case Constants.METHOD_CLEAR_ALL_POLYLINES:
                removeAllPolylines(call, result);
                break;
        }
    }

    private void removeAllPolylines(MethodCall call, MethodChannel.Result result){
        try {
            LogUtil.d(TAG, "removeAllPolylines");
            for (Map.Entry<String, Polyline> entry : currentPolylineMap.entrySet()) {
                Polyline polyline = entry.getValue();
                if (polyline != null) {
                    polyline.remove();
                }
            }
            currentPolylineMap.clear();
            result.success(null);
        } catch (Exception e) {
            LogUtil.d(TAG, "removeAllPolylines error===>" + e.getMessage());
            result.error("JsonSyntaxException", e.getMessage(), null);
        }
    }

    private void removePolyLine(MethodCall call, MethodChannel.Result result) {
        try {
            Map<String, Object> arguments = call.arguments();
            if (arguments == null) {
                result.error("arguments is null", null, null);
                return;
            }
            String lineId = ParamUtil.getString(arguments, "lineId");
            LogUtil.d(TAG, "removePolyline lineId===>" + lineId);
            Polyline polyline = currentPolylineMap.get(lineId);
            if (polyline != null) {
                polyline.remove();
                currentPolylineMap.remove(lineId);
            }
            result.success(null);
        } catch (Exception e) {
            LogUtil.d(TAG, "removePolyline error===>" + e.getMessage());
            result.error("JsonSyntaxException", e.getMessage(), null);
        }
    }

    private void addPolyline(MethodCall call, MethodChannel.Result result) {
        try {
            Map<String, Object> arguments = call.arguments();
            if (arguments == null) {
                result.error("arguments is null", null, null);
                return;
            }
            String lineId = ParamUtil.getString(arguments, "lineId");
            boolean isAnimateCamera = ParamUtil.getBoolean(arguments, "isAnimateCamera", true);
            LogUtil.d(TAG, "isAnimateCamera===>" + isAnimateCamera);
            String points = (String) arguments.get("points");
            if (points == null || points.isEmpty()) {
                result.error("latLngList is null", null, null);
                return;
            }
            List<LatLng> latLngList = gson.fromJson(points, new TypeToken<List<LatLng>>() {
            }.getType());
            LogUtil.d(TAG, "latLngList===>" + latLngList);
            if (latLngList == null || latLngList.isEmpty()) {
                result.error("latLngList is empty", null, null);
                return;
            }
            String lineType = ParamUtil.getString(arguments, "lineType");

            //获取颜色
            String color = ParamUtil.getString(arguments, "color");
            //获取宽度
            double width = ParamUtil.getDouble(arguments, "width", 8);

            drawTrackByPoints(lineId, latLngList, lineType, color, width);
            if (isAnimateCamera) {
                String paddingStr = (String) arguments.get("mapPadding");

                MapPadding padding = null;
                if (paddingStr != null && !paddingStr.isEmpty()) {
                    padding = gson.fromJson(paddingStr, MapPadding.class);
                }
                LogUtil.d(TAG, "padding===>" + padding);
                moveToSuitableLocation(latLngList, padding);
            }
            result.success(null);
        } catch (Exception e) {
            LogUtil.d(TAG, "addPolyline error===>" + e.getMessage());
            result.error("JsonSyntaxException", e.getMessage(), null);
        }
    }

    private void drawTrackByPoints(String lineId, List<LatLng> points, @PolylineType String lineType, String color, double width) {
        if (map == null || points == null || points.isEmpty()) {
            return;
        }

        PolylineOptions polylineOptions = new PolylineOptions()
                .setUseTexture(true)
                .width(SizeUtil.dp2px(context, (float) width));

        if (Objects.equals(PolylineType.ERROR, lineType)) {
            polylineOptions.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.bg_map_error_line));
        } else if (Objects.equals(PolylineType.SELECTED, lineType)) {
            polylineOptions.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.bg_map_selected_line));
        } else if (Objects.equals(PolylineType.COLOR, lineType)) {
            if (!TextUtils.isEmpty(color)) {
                polylineOptions.color(Color.parseColor(color));
            }
        } else {
            polylineOptions.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.bg_map_line));
        }


        LatLng lastPoint = null;
        for (int i = 0; i < points.size(); i++) {
            LatLng currentPoint = points.get(i);
            if (lastPoint == null || lastPoint.latitude != currentPoint.latitude
                    || lastPoint.longitude != currentPoint.longitude) {
                polylineOptions.add(currentPoint);
                lastPoint = currentPoint;
            }
        }
        Polyline polyline = map.addPolyline(polylineOptions);
        currentPolylineMap.put(lineId, polyline);
    }

    private void moveToSuitableLocation(List<LatLng> points, MapPadding padding) {
        if (map == null) {
            return;
        }
        LatLngBounds.Builder builder = LatLngBounds.builder();
        for (int i = 0; i < points.size(); i++) {
            LatLng latLng = points.get(i);
            builder.include(latLng);
        }
        LatLngBounds bounds = builder.build();
        int left = 0;
        int top = 0;
        int right = 0;
        int bottom = 0;
        if (padding != null) {
            left = (int) SizeUtil.dp2px(context, padding.getLeft());
            top = (int) SizeUtil.dp2px(context, padding.getTop());
            right = (int) SizeUtil.dp2px(context, padding.getRight());
            bottom = (int) SizeUtil.dp2px(context, padding.getBottom());
        }
        LogUtil.d(TAG, "left===>" + left + "  top===>" + top + "  right===>" + right + "  bottom===>" + bottom);
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBoundsRect(bounds, left, right, top, bottom);
        map.animateCamera(cameraUpdate);
    }

    @Override
    public String[] getRegisterMethodIdArray() {
        return Constants.METHOD_ID_LIST_FOR_POLYLINE;
    }
}
