package me.km.plots;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import me.hammerle.snuviscript.code.ISnuviLogger;
import me.km.plots.PlotMap.Plot;
import me.km.world.WorldManager;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;

public class WorldPlotMap {
    private final HashMap<IWorld, PlotMap> maps = new HashMap<>();

    private final static int PLACE_FLAG = (1 << 0);
    private final static int BREAK_FLAG = (1 << 1);
    private final static int BUCKET_FLAG = (1 << 2);
    private final static int HIT_AMBIENT_FLAG = (1 << 3);
    private final static int BLOCK_INTERACT_FLAG = (1 << 4);
    private final static int ENTITY_INTERACT_FLAG = (1 << 5);

    public boolean canDoSomething(IWorld w, BlockPos pos, PlayerEntity p, int flag, boolean empty) {
        PlotMap map = maps.get(w);
        if(map == null) {
            return empty;
        }
        if(p == null) {
            return map.anyPlotMatches(pos.getX(), pos.getY(), pos.getZ(), empty, plot -> plot.hasFlags(flag));
        }
        UUID uuid = p.getUniqueID();
        return map.anyPlotMatches(pos.getX(), pos.getY(), pos.getZ(), empty,
                plot -> plot.hasFlags(flag) || plot.getOwners().contains(uuid));
    }

    public boolean canPlaceBlock(IWorld w, BlockPos pos, PlayerEntity p) {
        return canDoSomething(w, pos, p, PLACE_FLAG, true);
    }

    public boolean canBreakBlock(IWorld w, BlockPos pos, PlayerEntity p) {
        return canDoSomething(w, pos, p, BREAK_FLAG, true);
    }

    public boolean canUseBucket(IWorld w, BlockPos pos, PlayerEntity p) {
        return canDoSomething(w, pos, p, BUCKET_FLAG, true);
    }

    public boolean canHitAmbientEntity(IWorld w, BlockPos pos, PlayerEntity p) {
        return canDoSomething(w, pos, p, HIT_AMBIENT_FLAG, true);
    }

    public boolean canInteractWithBlock(IWorld w, BlockPos pos, PlayerEntity p) {
        return canDoSomething(w, pos, p, BLOCK_INTERACT_FLAG, true);
    }

    public boolean canInteractWithEntity(IWorld w, BlockPos pos, PlayerEntity p) {
        return canDoSomething(w, pos, p, ENTITY_INTERACT_FLAG, true);
    }

    public List<PlotMap.Plot> getPlots(IWorld w, BlockPos pos) {
        PlotMap map = maps.get(w);
        if(map == null) {
            return new ArrayList<>();
        }
        return map.getPlotAt(pos.getX(), pos.getY(), pos.getZ());
    }

    public PlotMap.Plot add(IWorld w, BlockPos pos1, BlockPos pos2) {
        PlotMap map = maps.get(w);
        if(map == null) {
            map = new PlotMap();
            maps.put(w, map);
        }
        return map.add(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ());
    }

    public void remove(IWorld w, Plot p) {
        PlotMap map = maps.get(w);
        if(map != null) {
            map.remove(p);
        }
    }

    public Iterator<PlotMap.Plot> getIterator(IWorld w) {
        PlotMap map = maps.get(w);
        if(map != null) {
            return map.getIterator();
        }
        return Collections.EMPTY_LIST.iterator();
    }

    public Iterator<PlotMap.Plot> getIterator(IWorld w, UUID uuid) {
        PlotMap map = maps.get(w);
        if(map != null) {
            return map.getIterator(uuid);
        }
        return Collections.EMPTY_LIST.iterator();
    }

    public List<Plot> getIntersectingPlots(IWorld w, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
        PlotMap map = maps.get(w);
        if(map != null) {
            return map.getIntersectingPlots(minX, minY, minZ, maxX, maxY, maxZ);
        }
        return Collections.EMPTY_LIST;
    }

    public void save() {
        File f = new File("plot_storage");
        f.mkdir();
        maps.entrySet().forEach((entry) -> {
            String name = WorldManager.getName(entry.getKey());
            entry.getValue().save("plot_storage/" + name);
        });
    }

    public void read(MinecraftServer ms, ISnuviLogger logger) {
        File dir = new File("plot_storage");
        if(!dir.exists()) {
            return;
        }
        for(File f : dir.listFiles()) {
            String name = f.getName();
            IWorld sw = WorldManager.get(ms, f.getName());
            if(sw == null) {
                logger.print(String.format("invalid world storage '%s'", name));
                continue;
            }
            PlotMap pm = new PlotMap();
            maps.put(sw, pm);
            pm.read(f);
        }
    }
}
