package land.chipmunk.chipmunkmod.config.migration;

import land.chipmunk.chipmunkmod.ChipmunkMod;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.transformation.ConfigurationTransformation;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

// Makes it easier for forks to add their own config versioning structure
public abstract class AbstractMigrationManager {
    private final List<ConfigMigration> migrations = new ArrayList<>();
    private final Object[] versionKey;

    public AbstractMigrationManager (final Object... versionKey) {
        this.versionKey = versionKey;
    }

    protected void register (final ConfigMigration migration) {
        this.migrations.add(migration);
    }

    protected void registerFrom (final int version, final Supplier<ConfigurationTransformation> supplier) {
        this.migrations.add(ConfigMigration.from(version, supplier));
    }

    public ConfigurationTransformation.Versioned create () {
        final ConfigurationTransformation.VersionedBuilder builder = ConfigurationTransformation.versionedBuilder()
                .versionKey(versionKey);

        this.migrations.forEach(migration -> builder.addVersion(migration.version(), migration.create()));

        return builder.build();
    }

    public <N extends ConfigurationNode> void setLatest (final N config) throws ConfigurateException {
        final ConfigurationTransformation.Versioned transforms = this.create();
        config.node(transforms.versionKey()).set(Integer.class, transforms.latestVersion());
    }

    public <N extends ConfigurationNode> boolean migrate (final N config) throws ConfigurateException {
        final ConfigurationTransformation.Versioned transforms = this.create();
        final int version = transforms.version(config);

        if (version > transforms.latestVersion()) {
            ChipmunkMod.LOGGER.warn("Latest config version is {}, but yours is {}! Are you from the future?",
                                    transforms.latestVersion(), version);
            return false;
        }

        transforms.apply(config);

        final int newVersion = transforms.version(config);
        if (version != newVersion) {
            ChipmunkMod.LOGGER.info("Migrated config from version {} to {}!", version, newVersion);
            return true;
        }

        return false;
    }
}
