package com.m2sdl.undercooked.map;


import android.content.Context;

import com.m2sdl.undercooked.utils.RestaurantCategories;

import org.mapsforge.core.graphics.Bitmap;
import org.mapsforge.core.model.LatLong;
import org.mapsforge.core.model.Point;
import org.mapsforge.core.model.Tile;
import org.mapsforge.map.android.view.MapView;
import org.mapsforge.map.datastore.MapDataStore;
import org.mapsforge.map.datastore.PointOfInterest;
import org.mapsforge.map.layer.GroupLayer;
import org.mapsforge.map.layer.cache.TileCache;
import org.mapsforge.map.model.MapViewPosition;
import org.mapsforge.map.model.common.Observer;
import org.mapsforge.map.util.LayerUtil;
import org.mapsforge.map.util.MapPositionUtil;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

// TODO : utiliser WayTextContainer + SymbolContainer
public class RestaurantLayerGroup extends GroupLayer implements Observer {
    private final TileCache tileCache;
    private final MapDataStore mapDataStore;
    private final MapViewPosition mapViewPosition;
    private final Bitmap bitmap;
    private final MapView mapView;
    Context context;
    private Tile upperLeft;
    private Tile lowerRight;

    public RestaurantLayerGroup(Context context, TileCache tileCache, MapDataStore mapDataStore, MapViewPosition mapViewPosition, Bitmap bitmap, MapView mapView) {
        this.context = context;
        this.tileCache = tileCache;
        this.mapDataStore = mapDataStore;
        this.mapViewPosition = mapViewPosition;
        this.bitmap = bitmap;
        this.mapView = mapView;
        registerAsObserver();
    }

    private static boolean isANamedRestaurant(PointOfInterest poi) {
        AtomicBoolean isNamed = new AtomicBoolean(false);
        AtomicBoolean isRestaurant = new AtomicBoolean(false);
        poi.tags.forEach(tag -> {
            if (RestaurantCategories.matches(tag.value)) {
                isRestaurant.set(true);
            }
            if (tag.key.equals("name")) {
                isNamed.set(true);
            }
        });
        return isRestaurant.get() && isNamed.get();
    }

    public synchronized void clearMarkers() {
        layers.clear();
    }

    private void registerAsObserver() {
        mapViewPosition.addObserver(this);
    }

    @Override
    public synchronized boolean onLongPress(LatLong tapLatLong, Point layerXY, Point tapXY) {
        if (isVisible()) {
            return super.onLongPress(tapLatLong, layerXY, tapXY);
        }
        return false;
    }

    @Override
    public synchronized boolean onTap(LatLong tapLatLong, Point layerXY, Point tapXY) {
        if (isVisible()) {
            return super.onTap(tapLatLong, layerXY, tapXY);
        }
        return false;
    }

    public synchronized void addMarker(RestaurantMarker marker) {
//        Log.d("AddMarkers", "addLayer: adding " + marker.toString());
        layers.add(marker);
    }

    @Override
    public void onChange() {
        if (isVisible()) {
            addRestaurantMarkers();
        }
    }

    private void addRestaurantMarkers() {
        // TODO : assert whether or not we need to search again
        // TODO : ajouter un marker + onClick sur un marker = afficher les infos
        var bb = MapPositionUtil.getBoundingBox(mapViewPosition.getMapPosition(), mapViewPosition.getRotation(), displayModel.getTileSize(), mapView.getDimension(), mapView.getMapViewCenterX(), mapView.getMapViewCenterY());
        var ul = LayerUtil.getUpperLeft(bb, mapViewPosition.getZoomLevel(), displayModel.getTileSize());
        var lr = LayerUtil.getLowerRight(bb, mapViewPosition.getZoomLevel(), displayModel.getTileSize());
        if (!Objects.equals(upperLeft, ul) || !Objects.equals(lowerRight, lr)) {
            clearMarkers();
            upperLeft = ul;
            lowerRight = lr;
            mapDataStore.readMapData(ul, lr).pois.parallelStream().filter(RestaurantLayerGroup::isANamedRestaurant)
//                    .limit(100)
                    .forEach(pointOfInterest -> addMarker(new RestaurantMarker(context, bitmap, pointOfInterest, mapView)));
        }
    }
}
