package com.livingworld.regions;

import java.util.UUID;

/**
 * Represents a region within the game world.
 *
 * <p>A Region encapsulates identity, spatial position, lifecycle state,
 * simulation metadata, flags, metrics, and module-specific data.</p>
 */
public class Region {

    private UUID id;
    private RegionCoordinate coordinate;
    private RegionLifecycleState lifecycleState;
    private long createdAtSimulationTick;
    private long lastUpdatedSimulationTick;
    private boolean dirty;
    private RegionFlags flags;
    private RegionMetrics metrics;
    private RegionModuleData moduleData;

    /**
     * Creates a new Region with the specified fields.
     *
     * @param id                     the unique identifier (must not be null)
     * @param coordinate             the spatial position (must not be null)
     * @param lifecycleState         the current lifecycle state (must not be null)
     * @param createdAtSimulationTick the simulation tick when this region was created
     * @param lastUpdatedSimulationTick the simulation tick of the last update
     * @param dirty                  whether the region has unsaved changes
     * @param flags                  the region flag state (must not be null)
     * @param metrics                the region metric data (must not be null)
     * @param moduleData             the module-specific data store (must not be null)
     * @throws IllegalArgumentException if any required field is null
     */
    public Region(UUID id, RegionCoordinate coordinate, RegionLifecycleState lifecycleState,
                  long createdAtSimulationTick, long lastUpdatedSimulationTick, boolean dirty,
                  RegionFlags flags, RegionMetrics metrics, RegionModuleData moduleData) {
        if (id == null) {
            throw new IllegalArgumentException("id must not be null");
        }
        if (coordinate == null) {
            throw new IllegalArgumentException("coordinate must not be null");
        }
        if (lifecycleState == null) {
            throw new IllegalArgumentException("lifecycleState must not be null");
        }
        if (flags == null) {
            throw new IllegalArgumentException("flags must not be null");
        }
        if (metrics == null) {
            throw new IllegalArgumentException("metrics must not be null");
        }
        if (moduleData == null) {
            throw new IllegalArgumentException("moduleData must not be null");
        }

        this.id = id;
        this.coordinate = coordinate;
        this.lifecycleState = lifecycleState;
        this.createdAtSimulationTick = createdAtSimulationTick;
        this.lastUpdatedSimulationTick = lastUpdatedSimulationTick;
        this.dirty = dirty;
        this.flags = flags;
        this.metrics = metrics;
        this.moduleData = moduleData;
    }

    // ------------------------------------------------------------------
    // Dirty tracking
    // ------------------------------------------------------------------

    /**
     * Marks this region as dirty, indicating unsaved changes.
     */
    public void markDirty() {
        this.dirty = true;
    }

    /**
     * Clears the dirty flag, indicating changes have been saved.
     */
    public void clearDirty() {
        this.dirty = false;
    }

    /**
     * Returns whether this region has unsaved changes.
     *
     * @return true if the region is dirty
     */
    public boolean isDirty() {
        return this.dirty;
    }

    // ------------------------------------------------------------------
    // Simulation tick management
    // ------------------------------------------------------------------

    /**
     * Updates the last simulated tick to the given value.
     *
     * @param tick the current simulation tick
     */
    public void updateLastSimulatedTick(long tick) {
        this.lastUpdatedSimulationTick = tick;
    }

    // ------------------------------------------------------------------
    // Lifecycle state management
    // ------------------------------------------------------------------

    /**
     * Sets the lifecycle state of this region.
     *
     * @param state the new lifecycle state (must not be null)
     * @throws IllegalArgumentException if state is null
     */
    public void setLifecycleState(RegionLifecycleState state) {
        if (state == null) {
            throw new IllegalArgumentException("lifecycleState must not be null");
        }
        this.lifecycleState = state;
    }

    // ------------------------------------------------------------------
    // Validation
    // ------------------------------------------------------------------

    /**
     * Validates that all required fields are non-null.
     *
     * @throws IllegalStateException if any required field is null
     */
    public void validate() {
        if (this.id == null) {
            throw new IllegalStateException("id must not be null");
        }
        if (this.coordinate == null) {
            throw new IllegalStateException("coordinate must not be null");
        }
        if (this.lifecycleState == null) {
            throw new IllegalStateException("lifecycleState must not be null");
        }
        if (this.flags == null) {
            throw new IllegalStateException("flags must not be null");
        }
        if (this.metrics == null) {
            throw new IllegalStateException("metrics must not be null");
        }
        if (this.moduleData == null) {
            throw new IllegalStateException("moduleData must not be null");
        }
    }

    // ------------------------------------------------------------------
    // Getters and setters
    // ------------------------------------------------------------------

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        if (id == null) {
            throw new IllegalArgumentException("id must not be null");
        }
        this.id = id;
    }

    public RegionCoordinate getCoordinate() {
        return coordinate;
    }

    public void setCoordinate(RegionCoordinate coordinate) {
        if (coordinate == null) {
            throw new IllegalArgumentException("coordinate must not be null");
        }
        this.coordinate = coordinate;
    }

    public RegionLifecycleState getLifecycleState() {
        return lifecycleState;
    }

    public long getCreatedAtSimulationTick() {
        return createdAtSimulationTick;
    }

    public void setCreatedAtSimulationTick(long createdAtSimulationTick) {
        this.createdAtSimulationTick = createdAtSimulationTick;
    }

    public long getLastUpdatedSimulationTick() {
        return lastUpdatedSimulationTick;
    }

    public RegionFlags getFlags() {
        return flags;
    }

    public void setFlags(RegionFlags flags) {
        if (flags == null) {
            throw new IllegalArgumentException("flags must not be null");
        }
        this.flags = flags;
    }

    public RegionMetrics getMetrics() {
        return metrics;
    }

    public void setMetrics(RegionMetrics metrics) {
        if (metrics == null) {
            throw new IllegalArgumentException("metrics must not be null");
        }
        this.metrics = metrics;
    }

    public RegionModuleData getModuleData() {
        return moduleData;
    }

    public void setModuleData(RegionModuleData moduleData) {
        if (moduleData == null) {
            throw new IllegalArgumentException("moduleData must not be null");
        }
        this.moduleData = moduleData;
    }

    // ------------------------------------------------------------------
    // Standard overrides
    // ------------------------------------------------------------------

    @Override
    public String toString() {
        return "Region{id=" + id + ", coordinate=" + coordinate +
                ", lifecycleState=" + lifecycleState + "}";
    }
}