/*
 * Copyright (C) 2025  Tim Zimmermann <tim@aglais.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.aglais.zms.util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.function.Supplier;

/**
 * Class for interacting with JSON-based configuration files
 */
public class ConfigUtil {

    private static final String LOG_TAG = ConfigUtil.class.getSimpleName();
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    /**
     * Save a JSON config to the given path
     *
     * @param configPath The config file path
     * @param config     The config object to write to the file
     * @param <T>        The config type
     */
    public static <T> void saveConfig(String configPath, T config) {
        File configFile = new File(configPath).getAbsoluteFile();

        if (!configFile.exists()) {
            File parent = configFile.getParentFile();

            if (!parent.exists() && !parent.mkdirs()) {
                Log.e(LOG_TAG, "Failed to create directory: " + parent.getAbsolutePath());
                return;
            }
        }

        try (FileWriter configWriter = new FileWriter(configFile)) {
            GSON.toJson(config, configWriter);
        } catch (IOException e) {
            Log.e(LOG_TAG, "Failed to save config file: " + configFile.getAbsolutePath(), e);
        }
    }

    /**
     * Load a JSON config from the given path
     *
     * @param configPath            The config file path
     * @param configClass           The class used for JSON (de)serialization
     * @param defaultConfigSupplier {@link Supplier} for the default config object to write to the file if it is nonexistent
     * @param <T>                   The config type
     * @return A config object of the given type
     */
    @NotNull
    public static <T> T loadConfig(String configPath, Class<T> configClass, Supplier<T> defaultConfigSupplier) {
        T config = null;

        File configFile = new File(configPath).getAbsoluteFile();
        if (!configFile.exists()) {
            saveConfig(configPath, defaultConfigSupplier.get());
        }

        try (FileReader configReader = new FileReader(configFile)) {
            config = GSON.fromJson(configReader, configClass);
        } catch (IOException e) {
            Log.e(LOG_TAG, "Failed to read config file: " + configFile.getAbsolutePath(), e);
        }

        if (config == null) {
            Log.e(LOG_TAG, "Failed to load config: " + configFile.getAbsolutePath());

            return defaultConfigSupplier.get();
        }

        return config;
    }

}
