/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   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 <https://www.gnu.org/licenses/>.
 */

package de.steamwar.bausystem.region.fixed;

import de.steamwar.bausystem.region.FlagOptional;
import de.steamwar.bausystem.region.FlagStorage;
import de.steamwar.bausystem.region.RegionFlagPolicy;
import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.worlddata.WorldData;
import de.steamwar.core.Core;
import lombok.NonNull;
import yapion.hierarchy.types.YAPIONObject;

import java.util.HashMap;
import java.util.Map;

public class FixedFlagStorage implements FlagStorage {

    private Map<Flag<?>, Flag.Value<?>> flagMap = new HashMap<>();
    private YAPIONObject data;

    public FixedFlagStorage(YAPIONObject data) {
        this.data = data;
        for (final Flag flag : Flag.getFlags()) {
            if (!has(flag).isWritable()) continue;
            try {
                String s = data.getPlainValue(flag.name());
                flagMap.put(flag, flag.valueOfValue(s));
            } catch (Exception e) {
                flagMap.put(flag, (Flag.Value<?>) flag.getDefaultValue());
            }
        }
    }

    @Override
    public @NonNull <T extends Enum<T> & Flag.Value<T>> RegionFlagPolicy has(@NonNull Flag<T> flag) {
        if (flag.oneOf(Flag.COLOR, Flag.TNT, Flag.FIRE, Flag.FREEZE, Flag.PROTECT, Flag.NO_GRAVITY, Flag.CHANGED)) {
            return RegionFlagPolicy.WRITABLE;
        }
        if (flag.oneOf(Flag.ITEMS) && Core.getVersion() >= 20) {
            return RegionFlagPolicy.WRITABLE;
        }
        if (flag.oneOf(Flag.TESTBLOCK)) {
            return RegionFlagPolicy.READ_ONLY;
        }
        return RegionFlagPolicy.NOT_APPLICABLE;
    }

    @Override
    public <T extends Enum<T> & Flag.Value<T>> boolean set(@NonNull Flag<T> flag, @NonNull T value) {
        if (has(flag).isWritable()) {
            boolean hasChanged = flagMap.put(flag, value) != value;
            if (hasChanged) {
                data.put(flag.name(), value.name());
                WorldData.write();
            }
            return hasChanged;
        } else {
            return false;
        }
    }

    @Override
    public @NonNull <T extends Enum<T> & Flag.Value<T>> FlagOptional<T> get(@NonNull Flag<T> flag) {
        return FlagOptional.of(flag, (T) flagMap.get(flag));
    }

    @Override
    public void clear() {
        flagMap.clear();
    }

    @Override
    public Map<Flag<?>, Flag.Value<?>> getBackedMap() {
        return flagMap;
    }

    @Override
    public String toString() {
        return "FixedFlagStorage{" +
                "flagMap=" + flagMap +
                '}';
    }
}
