package com.tiedup.remake.entities;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.ModItems;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.state.CollarRegistry;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.util.tasks.ItemTask;
import com.tiedup.remake.util.tasks.JobLoader;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.UUID;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;

/**
 * Manages the job system for EntityKidnapper.
 *
 * <p>The job system allows kidnappers to assign tasks to their captives.
 * When a job is assigned:
 * <ol>
 *   <li>Worker UUID is stored for tracking</li>
 *   <li>Shock collar is put on the worker</li>
 *   <li>Worker is untied and freed to complete the job</li>
 *   <li>Kidnapper waits for job completion</li>
 * </ol>
 *
 * <p>This system IS persisted to NBT via {@link #save(CompoundTag)} and {@link #load(CompoundTag)}.
 */
public class KidnapperJobManager {

    private final EntityKidnapper kidnapper;

    /** Current job assigned to worker. */
    @Nullable
    private ItemTask currentJob = null;

    /** UUID of worker doing the current job (freed but tracked). */
    @Nullable
    private UUID jobWorkerUUID = null;

    public KidnapperJobManager(EntityKidnapper kidnapper) {
        this.kidnapper = kidnapper;
    }

    // STATE QUERIES

    /**
     * Check if waiting for worker to complete job.
     * Note: Worker is NOT a captive during job - they are tracked by UUID.
     */
    public boolean isWaitingForJobToBeCompleted() {
        return this.currentJob != null && this.jobWorkerUUID != null;
    }

    /**
     * Get the current job assigned to worker.
     */
    @Nullable
    public ItemTask getCurrentJob() {
        return this.currentJob;
    }

    /**
     * Get the UUID of the worker doing the current job.
     */
    @Nullable
    public UUID getJobWorkerUUID() {
        return this.jobWorkerUUID;
    }

    /**
     * Set the UUID of the worker doing the current job.
     * Used by maids to register labor workers for attack protection.
     */
    public void setJobWorkerUUID(@Nullable UUID workerUUID) {
        this.jobWorkerUUID = workerUUID;
    }

    /**
     * Find the job worker entity by UUID.
     * @return The worker as Player, or null if not found/offline
     */
    @Nullable
    public Player getJobWorker() {
        if (this.jobWorkerUUID == null) {
            return null;
        }
        return kidnapper.level().getPlayerByUUID(this.jobWorkerUUID);
    }

    // JOB ASSIGNMENT

    /**
     * Assign a job to the kidnapper's current captive.
     * This will:
     * <ol>
     *   <li>Store the worker UUID</li>
     *   <li>Untie the captive (remove bind and gag)</li>
     *   <li>Free them from captivity</li>
     *   <li>Put a shock collar on them (AFTER untie)</li>
     * </ol>
     *
     * @param job The job to assign
     * @return true if job was assigned
     */
    public boolean assignJob(ItemTask job) {
        if (!kidnapper.hasCaptives() || job == null) {
            return false;
        }

        if (this.currentJob != null) {
            TiedUpMod.LOGGER.warn(
                "[KidnapperJobManager] {} already has an active job",
                kidnapper.getNpcName()
            );
            return false;
        }

        IBondageState captive = kidnapper.getCaptive();
        if (captive == null) {
            return false;
        }

        // Store job and worker info
        this.currentJob = job;
        this.jobWorkerUUID = captive.asLivingEntity().getUUID();

        TiedUpMod.LOGGER.info(
            "[KidnapperJobManager] {} assigned job to {}: {}",
            kidnapper.getNpcName(),
            captive.getKidnappedName(),
            job.toDisplayString()
        );

        // IMPORTANT: Order matters here!
        // 1. First untie (this clears ALL bondage slots including collar)
        // 2. Then free from captivity
        // 3. Finally put collar on (so it's not cleared by untie)

        // Untie the worker (remove bind and gag so they can work)
        captive.untie(false);

        TiedUpMod.LOGGER.info(
            "[KidnapperJobManager] {} untied {} for job",
            kidnapper.getNpcName(),
            captive.getKidnappedName()
        );

        // Free from captivity (they keep the collar, we track via UUID)
        captive.free(false);

        TiedUpMod.LOGGER.info(
            "[KidnapperJobManager] {} freed {} to complete job",
            kidnapper.getNpcName(),
            captive.getKidnappedName()
        );

        // Put a shock collar on the worker AFTER untie/free
        ItemStack shockCollar = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(
            net.minecraft.resources.ResourceLocation.fromNamespaceAndPath("tiedup", "shock_collar_auto"));
        // Add kidnapper as owner so the collar is linked
        CollarHelper.addOwner(
            shockCollar,
            kidnapper.getUUID(),
            kidnapper.getNpcName()
        );
        // Lock the collar so they can't remove it
        if (shockCollar.getItem() instanceof com.tiedup.remake.items.base.ILockable lockable) {
            shockCollar = lockable.setLocked(shockCollar, true);
        }
        captive.equip(BodyRegionV2.NECK, shockCollar);

        // Register collar in CollarRegistry for tracking
        registerJobCollar(captive.asLivingEntity(), shockCollar);

        TiedUpMod.LOGGER.info(
            "[KidnapperJobManager] {} put shock collar (locked, owned) on {}",
            kidnapper.getNpcName(),
            captive.getKidnappedName()
        );

        // Hold shocker controller
        kidnapper.setItemInHand(
            InteractionHand.MAIN_HAND,
            new ItemStack(ModItems.SHOCKER_CONTROLLER.get())
        );

        return true;
    }

    /**
     * Assign a random job using JobLoader.
     *
     * @return true if job was assigned
     */
    public boolean assignRandomJob() {
        return assignJob(JobLoader.getRandomJob());
    }

    /**
     * Clear the current job and worker tracking.
     */
    public void clearCurrentJob() {
        if (this.currentJob != null || this.jobWorkerUUID != null) {
            TiedUpMod.LOGGER.info(
                "[KidnapperJobManager] {} cleared job",
                kidnapper.getNpcName()
            );
            this.currentJob = null;
            this.jobWorkerUUID = null;

            // Clear held shocker controller
            kidnapper.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY);
        }
    }

    // COLLAR REGISTRY

    /**
     * Register a job collar in the CollarRegistry.
     * This allows tracking the worker via the collar system.
     *
     * @param wearer The entity wearing the collar
     * @param collarStack The collar ItemStack
     */
    private void registerJobCollar(LivingEntity wearer, ItemStack collarStack) {
        if (wearer == null || kidnapper.level().isClientSide()) {
            return;
        }

        if (!(kidnapper.level() instanceof ServerLevel serverLevel)) {
            return;
        }

        CollarRegistry registry = CollarRegistry.get(serverLevel);
        if (registry == null) {
            return;
        }

        // Register kidnapper as owner of the wearer
        registry.registerCollar(wearer.getUUID(), kidnapper.getUUID());

        TiedUpMod.LOGGER.debug(
            "[KidnapperJobManager] Registered job collar for {} owned by {}",
            wearer.getName().getString(),
            kidnapper.getNpcName()
        );
    }

    /**
     * Unregister a job collar from the CollarRegistry.
     * Called when the job is completed and collar is removed.
     *
     * @param wearer The entity whose collar is being removed
     */
    public void unregisterJobCollar(LivingEntity wearer) {
        if (wearer == null || kidnapper.level().isClientSide()) {
            return;
        }

        if (!(kidnapper.level() instanceof ServerLevel serverLevel)) {
            return;
        }

        CollarRegistry registry = CollarRegistry.get(serverLevel);
        if (registry == null) {
            return;
        }

        // Unregister the wearer
        registry.unregisterWearer(wearer.getUUID());

        TiedUpMod.LOGGER.debug(
            "[KidnapperJobManager] Unregistered job collar for {}",
            wearer.getName().getString()
        );
    }

    // NBT PERSISTENCE

    /**
     * Save job manager state to NBT.
     * @param tag The tag to save to
     */
    public void save(CompoundTag tag) {
        if (this.currentJob != null) {
            tag.put("CurrentJob", this.currentJob.save());
        }
        if (this.jobWorkerUUID != null) {
            tag.putUUID("JobWorkerUUID", this.jobWorkerUUID);
        }
    }

    /**
     * Load job manager state from NBT.
     * @param tag The tag to load from
     */
    public void load(CompoundTag tag) {
        if (tag.contains("CurrentJob")) {
            this.currentJob = ItemTask.load(tag.getCompound("CurrentJob"));
        }
        if (tag.contains("JobWorkerUUID")) {
            this.jobWorkerUUID = tag.getUUID("JobWorkerUUID");
        }
    }
}
