package com.tiedup.remake.prison;

import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.nbt.CompoundTag;

/**
 * Minimal prisoner data record.
 *
 * Replaces the complex 17-field CaptivityState with essential data only.
 * Labor-specific data is in LaborRecord, ransom data in RansomRecord.
 *
 * This is a simple mutable POJO for performance (no withXxx() overhead).
 */
public class PrisonerRecord {

    // ==================== CORE STATE ====================

    /** Current prisoner state */
    private PrisonerState state;

    /** When this state was last changed (game time) */
    private long stateTimestamp;

    // ==================== OWNERSHIP ====================

    /** UUID of the captor (kidnapper who captured) */
    @Nullable
    private UUID captorId;

    /** UUID of the camp this prisoner belongs to */
    @Nullable
    private UUID campId;

    /** UUID of the cell this prisoner is assigned to */
    @Nullable
    private UUID cellId;

    // ==================== PROTECTION ====================

    /** Protection expiry time (game time) - for PROTECTED state */
    private long protectionExpiry;

    // ==================== CONSTRUCTOR ====================

    public PrisonerRecord() {
        this.state = PrisonerState.FREE;
        this.stateTimestamp = 0;
        this.captorId = null;
        this.campId = null;
        this.cellId = null;
        this.protectionExpiry = 0;
    }

    public PrisonerRecord(PrisonerState state, long timestamp) {
        this.state = state;
        this.stateTimestamp = timestamp;
        this.captorId = null;
        this.campId = null;
        this.cellId = null;
        this.protectionExpiry = 0;
    }

    // ==================== GETTERS ====================

    public PrisonerState getState() {
        return state;
    }

    public long getStateTimestamp() {
        return stateTimestamp;
    }

    @Nullable
    public UUID getCaptorId() {
        return captorId;
    }

    @Nullable
    public UUID getCampId() {
        return campId;
    }

    @Nullable
    public UUID getCellId() {
        return cellId;
    }

    public long getProtectionExpiry() {
        return protectionExpiry;
    }

    // ==================== SETTERS ====================

    public void setState(PrisonerState state, long timestamp) {
        this.state = state;
        this.stateTimestamp = timestamp;
    }

    public void setCaptorId(@Nullable UUID captorId) {
        this.captorId = captorId;
    }

    public void setCampId(@Nullable UUID campId) {
        this.campId = campId;
    }

    public void setCellId(@Nullable UUID cellId) {
        this.cellId = cellId;
    }

    public void setProtectionExpiry(long protectionExpiry) {
        this.protectionExpiry = protectionExpiry;
    }

    // ==================== QUERY METHODS ====================

    /**
     * Check if player is protected from capture at the given time.
     */
    public boolean isProtected(long currentTime) {
        return (
            state == PrisonerState.PROTECTED || currentTime < protectionExpiry
        );
    }

    /**
     * Check if player can be targeted by kidnappers.
     */
    public boolean isTargetable(long currentTime) {
        return state.isTargetable() && !isProtected(currentTime);
    }

    /**
     * Check if player is under any form of captivity.
     */
    public boolean isCaptive() {
        return state.isCaptive();
    }

    /**
     * Check if player is imprisoned (in cell or working).
     */
    public boolean isImprisoned() {
        return state.isImprisoned();
    }

    /**
     * Get time since last state change in ticks.
     */
    public long getTimeInState(long currentTime) {
        return currentTime - stateTimestamp;
    }

    // ==================== SERIALIZATION ====================

    public CompoundTag save() {
        CompoundTag tag = new CompoundTag();

        tag.putString("state", state.name());
        tag.putLong("stateTimestamp", stateTimestamp);

        if (captorId != null) {
            tag.putUUID("captorId", captorId);
        }
        if (campId != null) {
            tag.putUUID("campId", campId);
        }
        if (cellId != null) {
            tag.putUUID("cellId", cellId);
        }
        tag.putLong("protectionExpiry", protectionExpiry);

        return tag;
    }

    public static PrisonerRecord load(CompoundTag tag) {
        PrisonerRecord record = new PrisonerRecord();

        try {
            record.state = PrisonerState.valueOf(tag.getString("state"));
        } catch (IllegalArgumentException e) {
            record.state = PrisonerState.FREE;
        }

        record.stateTimestamp = tag.getLong("stateTimestamp");

        if (tag.contains("captorId")) {
            record.captorId = tag.getUUID("captorId");
        }
        if (tag.contains("campId")) {
            record.campId = tag.getUUID("campId");
        }
        if (tag.contains("cellId")) {
            record.cellId = tag.getUUID("cellId");
        }
        record.protectionExpiry = tag.getLong("protectionExpiry");

        return record;
    }

    // ==================== RESET ====================

    /**
     * Reset to FREE state, clearing all ownership data.
     */
    public void reset(long timestamp) {
        this.state = PrisonerState.FREE;
        this.stateTimestamp = timestamp;
        this.captorId = null;
        this.campId = null;
        this.cellId = null;
        this.protectionExpiry = 0;
    }

    /**
     * Create a deep copy.
     */
    public PrisonerRecord copy() {
        PrisonerRecord copy = new PrisonerRecord();
        copy.state = this.state;
        copy.stateTimestamp = this.stateTimestamp;
        copy.captorId = this.captorId;
        copy.campId = this.campId;
        copy.cellId = this.cellId;
        copy.protectionExpiry = this.protectionExpiry;
        return copy;
    }

    @Override
    public String toString() {
        return String.format(
            "PrisonerRecord{state=%s, campId=%s, cellId=%s}",
            state,
            campId != null ? campId.toString().substring(0, 8) : "null",
            cellId != null ? cellId.toString().substring(0, 8) : "null"
        );
    }
}
