package com.tiedup.remake.entities.kidnapper.components;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityKidnapper;
import com.tiedup.remake.entities.KidnapperItemSelector;
import com.tiedup.remake.entities.KidnapperTheme;
import com.tiedup.remake.entities.KidnapperVariant;
import com.tiedup.remake.entities.skins.Gender;
import com.tiedup.remake.entities.skins.KidnapperSkinManager;
import com.tiedup.remake.items.base.ItemColor;
import java.util.UUID;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;

/**
 * KidnapperAppearance - Manages visual appearance and item selection.
 *
 * Handles:
 * - Kidnapper skin variants (texture selection)
 * - Item themes (bind/gag sets)
 * - Theme colors
 * - Item selection results
 * - Initialization and persistence
 *
 * <p><b>Medium complexity</b> - Lazy loading, synced data integration.</p>
 */
public class KidnapperAppearance {

    // FIELDS

    /** Parent entity for accessing static data accessors */
    private final EntityKidnapper entity;

    /** Host callbacks */
    private final IAppearanceHost host;

    /** DATA accessors passed in (cannot be moved due to Minecraft static requirements) */
    private final EntityDataAccessor<String> dataVariantId;
    private final EntityDataAccessor<String> dataTheme;
    private final EntityDataAccessor<String> dataThemeColor;

    /** Current kidnapper skin variant (volatile for thread-safe render access) */
    @Nullable
    private volatile KidnapperVariant kidnapperVariant;

    /** Current item theme */
    @Nullable
    private KidnapperTheme currentTheme;

    /** Current theme color */
    @Nullable
    private ItemColor themeColor;

    /** Selected items for this kidnapper */
    @Nullable
    private KidnapperItemSelector.SelectionResult itemSelection;

    // CONSTRUCTOR

    public KidnapperAppearance(
        EntityKidnapper entity,
        IAppearanceHost host,
        EntityDataAccessor<String> dataVariantId,
        EntityDataAccessor<String> dataTheme,
        EntityDataAccessor<String> dataThemeColor
    ) {
        this.entity = entity;
        this.host = host;
        this.dataVariantId = dataVariantId;
        this.dataTheme = dataTheme;
        this.dataThemeColor = dataThemeColor;
    }

    // VARIANT SYSTEM

    /**
     * Set kidnapper variant and name.
     */
    public void setKidnapperVariant(KidnapperVariant variant) {
        if (variant == null) {
            TiedUpMod.LOGGER.warn(
                "[KidnapperAppearance] Attempted to set null kidnapper variant"
            );
            return;
        }

        this.kidnapperVariant = variant;
        host.setEntityDataString(dataVariantId, variant.id());
        host.setSlimArms(variant.hasSlimArms());
        host.setGender(variant.gender());
        applyVariantName(variant);
    }

    /**
     * Get current kidnapper variant.
     */
    @Nullable
    public KidnapperVariant getKidnapperVariant() {
        // Try to load from synced variant ID first
        if (
            this.kidnapperVariant == null && !getKidnapperVariantId().isEmpty()
        ) {
            this.kidnapperVariant = lookupVariantById(getKidnapperVariantId());
        }
        // Fallback: compute from UUID if not yet synced (client-side race condition fix)
        if (this.kidnapperVariant == null) {
            this.kidnapperVariant = computeVariantForEntity(host.getUUID());
        }
        return this.kidnapperVariant;
    }

    /**
     * Lookup a variant by ID from the skin manager.
     * Delegates to entity's virtual method to allow subclass overrides.
     */
    protected KidnapperVariant lookupVariantById(String variantId) {
        return entity.lookupVariantById(variantId);
    }

    /**
     * Compute which variant to use based on UUID.
     * Delegates to entity's virtual method to allow subclass overrides.
     */
    protected KidnapperVariant computeVariantForEntity(UUID entityUUID) {
        return entity.computeVariantForEntity(entityUUID);
    }

    /**
     * Get the texture folder for this kidnapper type.
     * Delegates to entity's virtual method to allow subclass overrides.
     */
    protected String getVariantTextureFolder() {
        return entity.getVariantTextureFolder();
    }

    /**
     * Get the default variant ID for fallback.
     * Delegates to entity's virtual method to allow subclass overrides.
     */
    protected String getDefaultVariantId() {
        return entity.getDefaultVariantId();
    }

    /**
     * Apply the name from variant to this entity.
     * Delegates to entity's virtual method to allow subclass overrides.
     */
    protected void applyVariantName(KidnapperVariant variant) {
        entity.applyVariantName(variant);
    }

    /**
     * Get the NBT key for saving the variant.
     * Delegates to entity's virtual method to allow subclass overrides.
     */
    protected String getVariantNBTKey() {
        return entity.getVariantNBTKey();
    }

    /**
     * Get kidnapper variant ID (synced data).
     */
    public String getKidnapperVariantId() {
        return host.getEntityDataString(dataVariantId);
    }

    /**
     * Get the skin texture resource location.
     * Reads variant ID directly from synced entityData to work on LAN clients
     * where SkinManager is not populated.
     */
    public ResourceLocation getSkinTexture() {
        String variantId = getKidnapperVariantId();
        if (!variantId.isEmpty()) {
            return ResourceLocation.fromNamespaceAndPath(
                "tiedup",
                getVariantTextureFolder() + variantId + ".png"
            );
        }
        // Fallback to default
        return ResourceLocation.fromNamespaceAndPath(
            "tiedup",
            getVariantTextureFolder() + getDefaultVariantId() + ".png"
        );
    }

    /**
     * Invalidate variant cache (called when synced data updates from server).
     */
    public void invalidateVariantCache() {
        this.kidnapperVariant = null;
    }

    // INITIALIZATION

    /**
     * Initialize variant and theme when entity is first added to world.
     * Should only be called on server side.
     */
    public void initializeAppearance() {
        initializeVariantOnSpawn();
        initializeTheme();
    }

    /**
     * Initialize variant on spawn (server-side only).
     */
    protected void initializeVariantOnSpawn() {
        if (host.level() == null || host.level().isClientSide) {
            return;
        }

        // Only set variant if not already set
        if (this.kidnapperVariant == null) {
            KidnapperVariant variant = computeVariantForEntity(host.getUUID());
            setKidnapperVariant(variant);
        }
    }

    /**
     * Initialize theme (server-side only).
     */
    protected void initializeTheme() {
        if (host.level() == null || host.level().isClientSide) {
            return;
        }

        // Only initialize if not already set
        if (this.currentTheme == null) {
            this.itemSelection = selectItemsForKidnapper();
            this.currentTheme = this.itemSelection.theme;
            this.themeColor = this.itemSelection.color;

            // Sync to client
            host.setEntityDataString(dataTheme, this.currentTheme.name());
            if (this.themeColor != null) {
                host.setEntityDataString(
                    dataThemeColor,
                    this.themeColor.getName()
                );
            }
        }
    }

    /**
     * Select themed items for this kidnapper.
     * Delegates to entity's virtual method to allow subclass overrides.
     */
    protected KidnapperItemSelector.SelectionResult selectItemsForKidnapper() {
        return entity.selectItemsForKidnapper();
    }

    // THEME & ITEM SELECTION

    /**
     * Get current theme (lazy load from synced data if needed).
     */
    public KidnapperTheme getTheme() {
        if (this.currentTheme == null) {
            String themeName = host.getEntityDataString(dataTheme);
            if (!themeName.isEmpty()) {
                try {
                    this.currentTheme = KidnapperTheme.valueOf(themeName);
                } catch (IllegalArgumentException e) {
                    TiedUpMod.LOGGER.debug(
                        "[KidnapperAppearance] Invalid theme from synced data: {}",
                        themeName
                    );
                }
            }
        }
        return this.currentTheme;
    }

    /**
     * Get current theme color (lazy load from synced data if needed).
     */
    @Nullable
    public ItemColor getThemeColor() {
        if (this.themeColor == null) {
            String colorName = host.getEntityDataString(dataThemeColor);
            if (!colorName.isEmpty()) {
                this.themeColor = ItemColor.fromName(colorName);
            }
        }
        return this.themeColor;
    }

    /**
     * Get item selection result.
     */
    @Nullable
    public KidnapperItemSelector.SelectionResult getItemSelection() {
        return this.itemSelection;
    }

    // NBT SERIALIZATION

    /**
     * Save appearance data to NBT.
     */
    public void saveToNBT(CompoundTag tag) {
        // Save kidnapper variant using NBT key
        if (this.kidnapperVariant != null) {
            tag.putString(getVariantNBTKey(), this.kidnapperVariant.id());
        }

        // Save theme and color
        if (this.currentTheme != null) {
            tag.putString("Theme", this.currentTheme.name());
        }
        if (this.themeColor != null) {
            tag.putString("ThemeColor", this.themeColor.getName());
        }
    }

    /**
     * Load appearance data from NBT.
     */
    public void loadFromNBT(CompoundTag tag) {
        // Restore kidnapper variant using NBT key and lookup
        String nbtKey = getVariantNBTKey();
        if (tag.contains(nbtKey)) {
            String variantId = tag.getString(nbtKey);
            KidnapperVariant variant = lookupVariantById(variantId);
            if (variant != null) {
                this.kidnapperVariant = variant;
                host.setEntityDataString(dataVariantId, variantId);
            }
        }

        // Restore theme and color
        if (tag.contains("Theme")) {
            try {
                this.currentTheme = KidnapperTheme.valueOf(
                    tag.getString("Theme")
                );
                host.setEntityDataString(dataTheme, this.currentTheme.name());
            } catch (IllegalArgumentException e) {
                TiedUpMod.LOGGER.debug(
                    "[KidnapperAppearance] Invalid theme from NBT: {}",
                    tag.getString("Theme")
                );
            }
        }
        if (tag.contains("ThemeColor")) {
            this.themeColor = ItemColor.fromName(tag.getString("ThemeColor"));
            if (this.themeColor != null) {
                host.setEntityDataString(
                    dataThemeColor,
                    this.themeColor.getName()
                );
            }
        }

        // Recreate item selection if theme was loaded
        if (this.currentTheme != null) {
            this.itemSelection = new KidnapperItemSelector.SelectionResult(
                this.currentTheme,
                this.themeColor,
                KidnapperItemSelector.createItemById(
                    this.currentTheme.getBindId(),
                    this.themeColor
                ),
                KidnapperItemSelector.createItemById(
                    this.currentTheme.getPrimaryGagId(),
                    this.themeColor
                ),
                KidnapperItemSelector.createMittens(),
                KidnapperItemSelector.createEarplugs(),
                this.currentTheme.hasBlindfolds()
                    ? KidnapperItemSelector.createItemById(
                          this.currentTheme.getPrimaryBlindfoldId(),
                          this.themeColor
                      )
                    : ItemStack.EMPTY
            );
        }
    }
}
