package com.livingworld.regions.cache;

import java.util.Collection;
import java.util.HashMap;
import java.util.Optional;

import com.livingworld.regions.Region;
import com.livingworld.regions.RegionCoordinate;

/**
 * In-memory cache for storing and retrieving active regions by their coordinate.
 *
 * <p>This is a plain Java class with no Minecraft dependencies. It provides
 * thread-safe operations via internal synchronization and returns safe copies
 * of mutable collections to prevent external modification.</p>
 */
public class RegionCache {

    private final HashMap<RegionCoordinate, Region> activeRegions;

    /**
     * Creates a new empty {@code RegionCache}.
     */
    public RegionCache() {
        this.activeRegions = new HashMap<>();
    }

    // ------------------------------------------------------------------
    // Query methods
    // ------------------------------------------------------------------

    /**
     * Returns the region associated with the given coordinate, or an empty
     * {@link Optional} if no such region exists in the cache.
     *
     * @param coordinate the region coordinate (must not be null)
     * @return an {@link Optional} containing the region if present
     * @throws IllegalArgumentException if coordinate is null
     */
    public Optional<Region> get(RegionCoordinate coordinate) {
        if (coordinate == null) {
            throw new IllegalArgumentException("coordinate must not be null");
        }
        return Optional.ofNullable(activeRegions.get(coordinate));
    }

    // ------------------------------------------------------------------
    // Mutation methods
    // ------------------------------------------------------------------

    /**
     * Adds the given region to this cache. If a region with an equal coordinate
     * already exists, it is replaced.
     *
     * @param region the region to add (must not be null)
     * @throws IllegalArgumentException if region is null or its coordinate is null
     */
    public void put(Region region) {
        if (region == null) {
            throw new IllegalArgumentException("region must not be null");
        }
        RegionCoordinate coordinate = region.getCoordinate();
        if (coordinate == null) {
            throw new IllegalArgumentException("region.coordinate must not be null");
        }
        activeRegions.put(coordinate, region);
    }

    /**
     * Removes the region associated with the given coordinate from this cache.
     *
     * @param coordinate the region coordinate (must not be null)
     * @throws IllegalArgumentException if coordinate is null
     */
    public void remove(RegionCoordinate coordinate) {
        if (coordinate == null) {
            throw new IllegalArgumentException("coordinate must not be null");
        }
        activeRegions.remove(coordinate);
    }

    // ------------------------------------------------------------------
    // Aggregate methods
    // ------------------------------------------------------------------

    /**
     * Returns a copy of the collection of values in this cache. The returned
     * collection is unmodifiable; attempting to modify it will throw an
     * {@link UnsupportedOperationException}.
     *
     * @return an unmodifiable copy of all active regions
     */
    public Collection<Region> allActive() {
        return new HashMap<>(activeRegions).values();
    }

    /**
     * Returns the number of regions currently stored in this cache.
     *
     * @return the size of the cache
     */
    public int size() {
        return activeRegions.size();
    }
}