package com.livingworld.modules;

import com.livingworld.events.LivingWorldEvent;
import com.livingworld.regions.Region;
import com.livingworld.data.serialization.PersistenceReader;
import com.livingworld.data.serialization.PersistenceWriter;

/**
 * Interface that all simulation modules must implement.
 *
 * <p>A SimulationModule is a self-contained unit of simulation logic that operates
 * on {@link Region} instances. Modules communicate through services, public data
 * contracts, or events -- never by directly mutating other systems.</p>
 *
 * <p>Modules receive a {@link ModuleContext} during initialisation which provides
 * access to registered core services. They must not create or depend on other
 * modules directly.</p>
 */
public interface SimulationModule {

    // ------------------------------------------------------------------
    // Identity
    // ------------------------------------------------------------------

    /**
     * Returns the unique module identifier.
     *
     * @return the module ID (must match {@code ModuleMetadata.moduleId()})
     */
    String getModuleId();

    /**
     * Returns the metadata describing this module.
     *
     * @return the module metadata (never null)
     */
    ModuleMetadata getMetadata();

    // ------------------------------------------------------------------
    // Lifecycle methods
    // ------------------------------------------------------------------

    /**
     * Initialises this module with access to core services.
     *
     * <p>This method is called once during module registration. Modules should
     * validate their configuration and prepare any internal state here.</p>
     *
     * @param context the module context providing service access (never null)
     * @throws IllegalArgumentException if context is null
     */
    void initialize(ModuleContext context);

    /**
     * Called when the server has fully started.
     *
     * <p>This method allows modules to perform any server-startup tasks such as
     * loading saved data or registering hooks.</p>
     *
     * @param context the server context (never null)
     */
    void onServerStarted(ServerContext context);

    // ------------------------------------------------------------------
    // Region operations
    // ------------------------------------------------------------------

    /**
     * Creates default module-specific data for a new region.
     *
     * <p>This method is called when a new region is created via {@link com.livingworld.regions.RegionFactory}.
     * The module should populate the region's {@code moduleData} with deterministic
     * defaults based on world seed and region coordinate where randomness is needed.</p>
     *
     * @param region the newly created region (never null)
     */
    void createDefaultRegionData(Region region);

    /**
     * Updates this module's logic for a specific region.
     *
     * <p>This method is called during each simulation cycle for regions that
     * are selected for update. Modules should return a {@link ModuleUpdateResult}
     * summarising any changes, events, or warnings rather than mutating global
     * systems directly.</p>
     *
     * @param context the region update context (never null)
     * @return the module update result (never null)
     */
    ModuleUpdateResult updateRegion(RegionUpdateContext context);

    // ------------------------------------------------------------------
    // Event handling
    // ------------------------------------------------------------------

    /**
     * Handles a Living World simulation event.
     *
     * <p>Modules should react to relevant events and return results through
     * {@link #updateRegion} rather than mutating systems directly.</p>
     *
     * @param event the event (never null)
     */
    void onLivingWorldEvent(LivingWorldEvent event);

    // ------------------------------------------------------------------
    // Persistence
    // ------------------------------------------------------------------

    /**
     * Saves this module's data to a persistence writer.
     *
     * <p>Modules must never write files directly. All serialisation goes through
     * the provided {@link PersistenceWriter} abstraction.</p>
     *
     * @param writer the persistence writer (never null)
     */
    void saveModuleData(PersistenceWriter writer);

    /**
     * Loads this module's data from a persistence reader.
     *
     * <p>This method is called during region loading to restore saved state.</p>
     *
     * @param reader the persistence reader (never null)
     */
    void loadModuleData(PersistenceReader reader);

    // ------------------------------------------------------------------
    // Shutdown
    // ------------------------------------------------------------------

    /**
     * Shuts down this module.
     *
     * <p>This method is called when the mod is being disabled or the server is
     * stopping. Modules should release any resources, close connections, and
     * perform cleanup here.</p>
     */
    void shutdown();
}