package com.tiedup.remake.blocks.entity;

import com.tiedup.remake.items.base.ILockable;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;

/**
 * BlockEntity for iron bar door blocks.
 *
 * Phase: Kidnapper Revamp - Cell System
 *
 * Stores the lock state and key UUID for the door.
 * Implements a block-based version of the ILockable pattern.
 */
public class IronBarDoorBlockEntity extends BlockEntity {

    @Nullable
    private UUID lockedByKeyUUID;

    private boolean locked = false;

    public IronBarDoorBlockEntity(BlockPos pos, BlockState state) {
        super(ModBlockEntities.IRON_BAR_DOOR.get(), pos, state);
    }

    // ==================== LOCK STATE ====================

    /**
     * Check if this door is locked.
     */
    public boolean isLocked() {
        return locked;
    }

    /**
     * Set the locked state.
     *
     * @param locked true to lock, false to unlock
     */
    public void setLocked(boolean locked) {
        this.locked = locked;
        if (!locked) {
            this.lockedByKeyUUID = null;
        }
        setChangedAndSync();
    }

    // ==================== KEY UUID ====================

    /**
     * Get the UUID of the key that locked this door.
     */
    @Nullable
    public UUID getLockedByKeyUUID() {
        return lockedByKeyUUID;
    }

    /**
     * Lock this door with a specific key.
     *
     * @param keyUUID The key UUID, or null to unlock
     */
    public void setLockedByKeyUUID(@Nullable UUID keyUUID) {
        this.lockedByKeyUUID = keyUUID;
        this.locked = keyUUID != null;
        setChangedAndSync();
    }

    /**
     * Check if a key matches this door's lock.
     *
     * @param keyUUID The key UUID to test
     * @return true if the key matches
     */
    public boolean matchesKey(UUID keyUUID) {
        if (keyUUID == null) return false;
        return lockedByKeyUUID != null && lockedByKeyUUID.equals(keyUUID);
    }

    /**
     * Check if this door can be unlocked by the given key.
     * Matches either the specific key or any master key.
     *
     * @param keyUUID The key UUID to test
     * @param isMasterKey Whether the key is a master key
     * @return true if the door can be unlocked
     */
    public boolean canUnlockWith(UUID keyUUID, boolean isMasterKey) {
        if (!locked) return true;
        if (isMasterKey) return true;
        return matchesKey(keyUUID);
    }

    // ==================== NBT SERIALIZATION ====================

    @Override
    public void load(CompoundTag tag) {
        super.load(tag);

        this.locked = tag.getBoolean(ILockable.NBT_LOCKED);

        if (tag.contains(ILockable.NBT_LOCKED_BY_KEY_UUID)) {
            this.lockedByKeyUUID = tag.getUUID(
                ILockable.NBT_LOCKED_BY_KEY_UUID
            );
        } else {
            this.lockedByKeyUUID = null;
        }
    }

    @Override
    protected void saveAdditional(CompoundTag tag) {
        super.saveAdditional(tag);

        tag.putBoolean(ILockable.NBT_LOCKED, locked);

        if (lockedByKeyUUID != null) {
            tag.putUUID(ILockable.NBT_LOCKED_BY_KEY_UUID, lockedByKeyUUID);
        }
    }

    // ==================== NETWORK SYNC ====================

    protected void setChangedAndSync() {
        if (level != null) {
            setChanged();
            level.sendBlockUpdated(
                worldPosition,
                getBlockState(),
                getBlockState(),
                3
            );
        }
    }

    @Override
    public CompoundTag getUpdateTag() {
        CompoundTag tag = super.getUpdateTag();
        tag.putBoolean(ILockable.NBT_LOCKED, locked);
        if (lockedByKeyUUID != null) {
            tag.putUUID(ILockable.NBT_LOCKED_BY_KEY_UUID, lockedByKeyUUID);
        }
        return tag;
    }

    @Nullable
    @Override
    public Packet<ClientGamePacketListener> getUpdatePacket() {
        return ClientboundBlockEntityDataPacket.create(this);
    }

    @Override
    public void handleUpdateTag(CompoundTag tag) {
        this.locked = tag.getBoolean(ILockable.NBT_LOCKED);
        if (tag.contains(ILockable.NBT_LOCKED_BY_KEY_UUID)) {
            this.lockedByKeyUUID = tag.getUUID(
                ILockable.NBT_LOCKED_BY_KEY_UUID
            );
        }
    }
}
