package dev.photosync.core.config;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.photosync.core.persistence.JsonFile;

import java.io.IOException;
import java.nio.file.Path;

/**
 * The two places PhotoSync's settings file may live, and the record of which
 * one is active.
 *
 * <p>Which location is active cannot be stored inside the settings file itself,
 * because the mod has to know where that file is before it can read it. So the
 * choice is recorded in a small marker ({@code location.json}) that always
 * lives in the instance directory: start-up reads the marker to pick a
 * directory, and the settings screen rewrites it when the player switches. A
 * missing or unreadable marker means the instance directory, which is also what
 * every existing installation has, so nothing changes for them.
 */
public final class ConfigLocations {

    private static final String MARKER_FILE = "location.json";

    private final Path instanceDirectory;
    private final Path userDirectory;
    private final JsonFile marker;

    public ConfigLocations(Path instanceDirectory, Path userDirectory) {
        this.instanceDirectory = instanceDirectory;
        this.userDirectory = userDirectory;
        this.marker = new JsonFile(instanceDirectory.resolve(MARKER_FILE));
    }

    /** A catalog that offers no user directory, for tests and the plain constructor. */
    public static ConfigLocations fixed(Path directory) {
        return new ConfigLocations(directory, directory);
    }

    /** The active location: what the marker says, or the instance when it says nothing. */
    public ConfigLocation resolve() {
        JsonElement stored = marker.readTree().orElse(null);
        if (stored == null || !stored.isJsonObject()) {
            return ConfigLocation.INSTANCE;
        }
        JsonElement value = stored.getAsJsonObject().get("location");
        if (value == null || !value.isJsonPrimitive()) {
            return ConfigLocation.INSTANCE;
        }
        try {
            return ConfigLocation.valueOf(value.getAsString());
        } catch (IllegalArgumentException e) {
            // A hand-edited marker names something that is not a location.
            return ConfigLocation.INSTANCE;
        }
    }

    /** The directory a location maps to. */
    public Path directory(ConfigLocation location) {
        return location == ConfigLocation.USER ? userDirectory : instanceDirectory;
    }

    /** Records the active location so the next launch looks in the right place. */
    public void writeMarker(ConfigLocation location) throws IOException {
        JsonObject written = new JsonObject();
        written.addProperty("location", location.name());
        marker.write(written);
    }
}
