package leigh.mud.engine;

import leigh.continuity.line.BasicLineHandlerFactory;
import leigh.continuity.net.TcpListener;
import leigh.mecha.lang.DangerousRunnable;
import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import leigh.mud.engine.io.CircleDataImporter;
import leigh.mud.engine.io.DataImporter;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.stream.Stream;

/**
 * The central class for the MUD engine.
 *
 * @author Alex Leigh
 */
public class MudEngine implements DangerousRunnable {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(MudEngine.class);

    private TcpListener listener = new TcpListener(
            new BasicLineHandlerFactory(new MudSessionFactory(this)), 4000);
    private HashMap<Integer, Room> rooms = new HashMap<>();
    private int startRoom;

    public static void main(String args[]) throws IOException {
        MudEngine engine = new MudEngine();
        engine.run();
    }

    public HashMap<Integer, Room> getRooms() {
        return rooms;
    }

    public Room getRoom(int id) {
        return rooms.get(id);
    }

    public MudEngine() throws IOException {
        //initRooms();
        initCircleRooms();
        logger.info("Loaded rooms. [cnt: {}]", rooms.size());
    }

    /**
     * Return the room that new players are placed into. Existing players should be returned to the room
     * they were in when their session was last closed.
     */
    public Room getNewPlayerRoom() {
        return rooms.get(startRoom);
    }

    /**
     * Load the world from CSV files.
     */
    public void initCsvRooms() throws IOException {
        DataImporter di = new DataImporter();
        di.readRooms(Path.of("leigh-mud/world/rooms.csv"));
        di.readExits(Path.of("leigh-mud/world/exits.csv"));
        di.readExtras(Path.of("leigh-mud/world/extras.csv"));

        for (Room r : di.getRooms()) {
            rooms.put(r.getId(), r);
        }

        startRoom = 5;
    }

    /**
     * Load the CircleMUD test files. This is intended to be used for dev/test purposes rather than suggested
     * as a production game.
     */
    public void initCircleRooms() throws IOException {
        try (Stream<Path> paths = Files.walk(Paths.get("leigh-mud/circle/world/wld/"))) {
            paths.filter(path -> !path.endsWith(".wld")).filter(path -> !Files.isDirectory(path)).forEach(path -> {
                CircleDataImporter loader = new CircleDataImporter(path.toFile());
                loader.run();
                for (Room r : loader.getRooms()) {
                    rooms.put(r.getId(), r);
                }
            });
        }

        startRoom = 3000;
    }

    @Override
    public void runDangerously() throws Exception {
        listener.runDangerously();
    }

    public synchronized Room createVoidRoom() {
        int x = 0;
        for (Room r : rooms.values()) {
            if (r.getId() > x) x = r.getId();
        }

        x++;

        Room v = new Room(x, "A void pocket.", "You are in a featureless void space.");
        rooms.put(x, v);
        return v;
    }

    @Override
    public void run() {
        try {
            runDangerously();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
