package com.tiedup.remake.prison;

import com.tiedup.remake.labor.LaborTask;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.nbt.CompoundTag;

/**
 * Labor-specific data for a prisoner.
 *
 * Separated from PrisonerRecord to keep concerns clean.
 * Contains task assignment, work phase, maid tracking, and activity monitoring.
 */
public class LaborRecord {

    /**
     * Sub-phases within the WORKING/IMPRISONED state.
     * More granular than PrisonerState, used by maid goals.
     */
    public enum WorkPhase {
        /** In cell, no task assigned */
        IDLE,
        /** Task assigned, waiting for extraction */
        PENDING_EXTRACTION,
        /** Being escorted to work area */
        EXTRACTING,
        /** Actively working on task */
        WORKING,
        /** Task complete, waiting for return */
        PENDING_RETURN,
        /** Being escorted back to cell */
        RETURNING,
        /** Back in cell, resting before next task */
        RESTING,
    }

    // ==================== TASK DATA ====================

    /** Current labor task (null if no task assigned) */
    @Nullable
    private LaborTask task;

    /** Current work phase */
    private WorkPhase phase;

    /** UUID of the maid managing this prisoner */
    @Nullable
    private UUID maidId;

    /** UUID of the maid currently escorting (during extract/return) */
    @Nullable
    private UUID escortMaidId;

    /** UUID of the guard entity assigned to this prisoner during labor */
    @Nullable
    private UUID guardId;

    // ==================== PROGRESS ====================

    /** Total emeralds earned through labor */
    private int totalEarned;

    /** Number of completed tasks this session */
    private int completedTasks;

    /** Shock level (0-3, escalating punishment for inactivity) */
    private int shockLevel;

    /** Whether the current/last task failed */
    private boolean taskFailed;

    // ==================== ACTIVITY TRACKING ====================

    /** Last time activity was detected */
    private long lastActivityTime;

    /** Last known position (for movement detection) */
    private int lastPosX, lastPosY, lastPosZ;

    /** When current phase started */
    private long phaseStartTime;

    // ==================== BONDAGE SNAPSHOT ====================

    /** Saved bondage state for restoration after labor */
    @Nullable
    private CompoundTag bondageSnapshot;

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

    public LaborRecord() {
        this.task = null;
        this.phase = WorkPhase.IDLE;
        this.maidId = null;
        this.escortMaidId = null;
        this.guardId = null;
        this.totalEarned = 0;
        this.completedTasks = 0;
        this.shockLevel = 0;
        this.taskFailed = false;
        this.lastActivityTime = 0;
        this.phaseStartTime = 0;
        this.bondageSnapshot = null;
    }

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

    @Nullable
    public LaborTask getTask() {
        return task;
    }

    public WorkPhase getPhase() {
        return phase;
    }

    @Nullable
    public UUID getMaidId() {
        return maidId;
    }

    @Nullable
    public UUID getEscortMaidId() {
        return escortMaidId;
    }

    @Nullable
    public UUID getGuardId() {
        return guardId;
    }

    public int getTotalEarned() {
        return totalEarned;
    }

    public int getCompletedTasks() {
        return completedTasks;
    }

    public int getShockLevel() {
        return shockLevel;
    }

    public boolean isTaskFailed() {
        return taskFailed;
    }

    public long getLastActivityTime() {
        return lastActivityTime;
    }

    public long getPhaseStartTime() {
        return phaseStartTime;
    }

    @Nullable
    public CompoundTag getBondageSnapshot() {
        return bondageSnapshot;
    }

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

    public void setTask(@Nullable LaborTask task) {
        this.task = task;
    }

    public void setPhase(WorkPhase phase, long currentTime) {
        this.phase = phase;
        this.phaseStartTime = currentTime;
    }

    public void setMaidId(@Nullable UUID maidId) {
        this.maidId = maidId;
    }

    public void setEscortMaidId(@Nullable UUID escortMaidId) {
        this.escortMaidId = escortMaidId;
    }

    public void setGuardId(@Nullable UUID guardId) {
        this.guardId = guardId;
    }

    public void setTotalEarned(int totalEarned) {
        this.totalEarned = totalEarned;
    }

    public void addEarnings(int amount) {
        this.totalEarned += amount;
    }

    public void incrementCompletedTasks() {
        this.completedTasks++;
    }

    public void setShockLevel(int shockLevel) {
        this.shockLevel = Math.max(0, Math.min(3, shockLevel));
    }

    public void incrementShockLevel() {
        setShockLevel(shockLevel + 1);
    }

    public void resetShockLevel() {
        this.shockLevel = 0;
    }

    public void setTaskFailed(boolean taskFailed) {
        this.taskFailed = taskFailed;
    }

    public void updateActivity(long currentTime, int x, int y, int z) {
        this.lastActivityTime = currentTime;
        this.lastPosX = x;
        this.lastPosY = y;
        this.lastPosZ = z;
    }

    public void setBondageSnapshot(@Nullable CompoundTag snapshot) {
        this.bondageSnapshot = snapshot != null ? snapshot.copy() : null;
    }

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

    /**
     * Check if a task is currently assigned.
     */
    public boolean hasTask() {
        return task != null;
    }

    /**
     * Check if currently being escorted.
     */
    public boolean isBeingEscorted() {
        return phase == WorkPhase.EXTRACTING || phase == WorkPhase.RETURNING;
    }

    /**
     * Check if can be assigned a new task.
     */
    public boolean canAssignTask() {
        return phase == WorkPhase.IDLE || phase == WorkPhase.RESTING;
    }

    /**
     * Check if prisoner has moved from last known position.
     */
    public boolean hasMovedFrom(int x, int y, int z, int threshold) {
        int dx = Math.abs(x - lastPosX);
        int dy = Math.abs(y - lastPosY);
        int dz = Math.abs(z - lastPosZ);
        return dx > threshold || dy > threshold || dz > threshold;
    }

    /**
     * Get time in current phase.
     */
    public long getTimeInPhase(long currentTime) {
        return currentTime - phaseStartTime;
    }

    // ==================== LIFECYCLE ====================

    /**
     * Assign a new task.
     */
    public void assignTask(LaborTask task, UUID maidId, long currentTime) {
        if (!canAssignTask()) {
            return; // Guard: only assign during IDLE or RESTING
        }
        this.task = task;
        this.maidId = maidId;
        this.phase = WorkPhase.PENDING_EXTRACTION;
        this.phaseStartTime = currentTime;
        this.taskFailed = false;
        this.shockLevel = 0;
    }

    /**
     * Start extraction (maid is coming to get prisoner).
     */
    public void startExtraction(UUID escortMaidId, long currentTime) {
        this.escortMaidId = escortMaidId;
        this.phase = WorkPhase.EXTRACTING;
        this.phaseStartTime = currentTime;
    }

    /**
     * Extraction complete, prisoner is now working.
     */
    public void startWorking(long currentTime) {
        this.phase = WorkPhase.WORKING;
        this.phaseStartTime = currentTime;
        this.lastActivityTime = currentTime;
        this.escortMaidId = null;
    }

    /**
     * Task complete, waiting for maid to return prisoner.
     */
    public void completeTask(long currentTime) {
        this.phase = WorkPhase.PENDING_RETURN;
        this.phaseStartTime = currentTime;
    }

    /**
     * Task failed (timeout or abandoned).
     */
    public void failTask(long currentTime) {
        this.taskFailed = true;
        this.phase = WorkPhase.PENDING_RETURN;
        this.phaseStartTime = currentTime;
    }

    /**
     * Start return to cell.
     */
    public void startReturn(UUID escortMaidId, long currentTime) {
        this.escortMaidId = escortMaidId;
        this.phase = WorkPhase.RETURNING;
        this.phaseStartTime = currentTime;
    }

    /**
     * Returned to cell, start rest period.
     */
    public void startRest(long currentTime) {
        if (!taskFailed) {
            incrementCompletedTasks();
        }
        this.task = null;
        this.phase = WorkPhase.RESTING;
        this.phaseStartTime = currentTime;
        this.escortMaidId = null;
        this.guardId = null;
        this.bondageSnapshot = null; // Clear after restoration
    }

    /**
     * Rest complete, back to idle.
     */
    public void finishRest(long currentTime) {
        this.phase = WorkPhase.IDLE;
        this.phaseStartTime = currentTime;
        this.taskFailed = false;
    }

    /**
     * Reset all labor data (on release).
     */
    public void reset() {
        this.task = null;
        this.phase = WorkPhase.IDLE;
        this.maidId = null;
        this.escortMaidId = null;
        this.guardId = null;
        this.totalEarned = 0;
        this.completedTasks = 0;
        this.shockLevel = 0;
        this.taskFailed = false;
        this.lastActivityTime = 0;
        this.phaseStartTime = 0;
        this.bondageSnapshot = null;
    }

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

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

        if (task != null) {
            tag.put("task", task.save());
        }
        tag.putString("phase", phase.name());

        if (maidId != null) {
            tag.putUUID("maidId", maidId);
        }
        if (escortMaidId != null) {
            tag.putUUID("escortMaidId", escortMaidId);
        }
        if (guardId != null) {
            tag.putUUID("guardId", guardId);
        }

        tag.putInt("totalEarned", totalEarned);
        tag.putInt("completedTasks", completedTasks);
        tag.putInt("shockLevel", shockLevel);
        tag.putBoolean("taskFailed", taskFailed);

        tag.putLong("lastActivityTime", lastActivityTime);
        tag.putInt("lastPosX", lastPosX);
        tag.putInt("lastPosY", lastPosY);
        tag.putInt("lastPosZ", lastPosZ);
        tag.putLong("phaseStartTime", phaseStartTime);

        if (bondageSnapshot != null) {
            tag.put("bondageSnapshot", bondageSnapshot.copy());
        }

        return tag;
    }

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

        if (tag.contains("task")) {
            record.task = LaborTask.load(tag.getCompound("task"));
        }

        try {
            record.phase = WorkPhase.valueOf(tag.getString("phase"));
        } catch (IllegalArgumentException e) {
            record.phase = WorkPhase.IDLE;
        }

        if (tag.contains("maidId")) {
            record.maidId = tag.getUUID("maidId");
        }
        if (tag.contains("escortMaidId")) {
            record.escortMaidId = tag.getUUID("escortMaidId");
        }
        if (tag.contains("guardId")) {
            record.guardId = tag.getUUID("guardId");
        }

        record.totalEarned = tag.getInt("totalEarned");
        record.completedTasks = tag.getInt("completedTasks");
        record.shockLevel = tag.getInt("shockLevel");
        record.taskFailed = tag.getBoolean("taskFailed");

        record.lastActivityTime = tag.getLong("lastActivityTime");
        record.lastPosX = tag.getInt("lastPosX");
        record.lastPosY = tag.getInt("lastPosY");
        record.lastPosZ = tag.getInt("lastPosZ");
        record.phaseStartTime = tag.getLong("phaseStartTime");

        if (tag.contains("bondageSnapshot")) {
            record.bondageSnapshot = tag.getCompound("bondageSnapshot").copy();
        }

        return record;
    }

    @Override
    public String toString() {
        return String.format(
            "LaborRecord{phase=%s, task=%s, earned=%d}",
            phase,
            task != null ? task.getDescription() : "none",
            totalEarned
        );
    }
}
