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

import com.tiedup.remake.entities.DamselVariant;
import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.entities.skins.DamselSkinManager;
import com.tiedup.remake.entities.skins.Gender;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;

/**
 * Manages the visual appearance of a Damsel NPC.
 * Responsibilities:
 * - Variant selection and management
 * - Skin texture resolution
 * - Gender
 * - Slim arms flag
 * - Custom name
 *
 */
public class DamselAppearance {

    private final EntityDamsel entity;

    /**
     * Current skin variant (cached from DATA_VARIANT_ID).
     * Thread-safe: accessed from render thread.
     */
    @Nullable
    private volatile DamselVariant variant;

    /**
     * Default texture for damsel entities.
     */
    private static final ResourceLocation DEFAULT_DAMSEL_TEXTURE =
        ResourceLocation.fromNamespaceAndPath(
            "tiedup",
            "textures/entity/damsel/dam_mob_1.png"
        );

    public DamselAppearance(EntityDamsel entity) {
        this.entity = entity;
    }

    // VARIANT SYSTEM

    /**
     * Get the current variant.
     * Lazy-loads from DATA_VARIANT_ID if not cached.
     */
    @Nullable
    public DamselVariant getVariant() {
        // Try to load from synced variant ID first
        if (this.variant == null && !this.getVariantId().isEmpty()) {
            this.variant = DamselSkinManager.CORE.getVariant(
                this.getVariantId()
            );
        }
        // Fallback: compute from UUID if not yet synced (client-side race condition fix)
        if (this.variant == null) {
            this.variant = DamselSkinManager.CORE.getVariantForEntity(
                this.entity.getUUID()
            );
        }
        return this.variant;
    }

    /**
     * Set the variant.
     * Updates both cache and synced data.
     */
    public void setVariant(DamselVariant variant) {
        this.variant = variant;
        this.entity.getEntityData().set(
            EntityDamsel.DATA_VARIANT_ID,
            variant.id()
        );
        this.setSlimArms(variant.hasSlimArms());
        this.setGender(variant.gender());
        applyVariantName(variant);
    }

    /**
     * Apply the name from variant to this entity.
     * Numbered variants (dam_mob_*) get random names.
     * Named variants (Anastasia, Blizz, etc.) use their default name.
     */
    protected void applyVariantName(DamselVariant variant) {
        if (variant.id().startsWith("dam_mob_")) {
            this.setNpcName(
                com.tiedup.remake.util.NameGenerator.getRandomDamselName()
            );
        } else {
            this.setNpcName(variant.defaultName());
        }
    }

    /**
     * Get variant ID (synced data).
     */
    public String getVariantId() {
        return this.entity.getEntityData().get(EntityDamsel.DATA_VARIANT_ID);
    }

    /**
     * Invalidate variant cache (called when DATA_VARIANT_ID changes).
     */
    public void invalidateVariantCache() {
        this.variant = null;
    }

    // SLIM ARMS

    /**
     * Check if this damsel uses slim arms model.
     * Reads from synced entityData - no local skin JSONs needed on client.
     */
    public boolean hasSlimArms() {
        return this.entity.getEntityData().get(EntityDamsel.DATA_SLIM_ARMS);
    }

    /**
     * Set slim arms flag directly.
     * Used by subclasses that have their own variant systems.
     */
    protected void setSlimArms(boolean slimArms) {
        this.entity.getEntityData().set(EntityDamsel.DATA_SLIM_ARMS, slimArms);
    }

    // GENDER

    public void setGender(Gender gender) {
        this.entity.getEntityData().set(
            EntityDamsel.DATA_GENDER,
            gender.getSerializedName()
        );
    }

    public Gender getGender() {
        return Gender.fromName(
            this.entity.getEntityData().get(EntityDamsel.DATA_GENDER)
        );
    }

    // SKIN TEXTURE

    /**
     * Get the skin texture for this entity.
     * Computes texture path from variant ID - no local skin JSONs needed on client.
     * Implements ISkinnedEntity to eliminate instanceof cascades in renderers.
     */
    public ResourceLocation getSkinTexture() {
        String variantId = this.getVariantId();
        if (!variantId.isEmpty()) {
            return ResourceLocation.fromNamespaceAndPath(
                "tiedup",
                "textures/entity/damsel/" + variantId + ".png"
            );
        }
        return DEFAULT_DAMSEL_TEXTURE;
    }

    // NAME SYSTEM

    /**
     * Get NPC's custom name.
     */
    public String getNpcName() {
        return this.entity.getEntityData().get(EntityDamsel.DATA_DAMSEL_NAME);
    }

    /**
     * Set NPC's custom name.
     * Also updates Minecraft's custom name display.
     */
    public void setNpcName(String name) {
        this.entity.getEntityData().set(EntityDamsel.DATA_DAMSEL_NAME, name);

        // Make the name visible in-game
        this.entity.setCustomName(Component.literal(name));
        this.entity.setCustomNameVisible(true);
    }

    // NBT SERIALIZATION

    /**
     * Save appearance data to NBT tag.
     * Writes directly to top-level keys for backward compatibility.
     */
    public void saveToTag(CompoundTag tag) {
        String variantId = this.entity.getEntityData().get(
            EntityDamsel.DATA_VARIANT_ID
        );
        if (!variantId.isEmpty()) {
            tag.putString("Variant", variantId);
        }

        String name = this.getNpcName();
        if (!name.isEmpty()) {
            tag.putString("DamselName", name);
        }

        tag.putBoolean("SlimArms", this.hasSlimArms());
        tag.putString("Gender", this.getGender().getSerializedName());
    }

    /**
     * Load appearance data from NBT tag.
     * Reads from top-level keys for backward compatibility.
     */
    public void loadFromTag(CompoundTag tag) {
        if (tag.contains("Variant")) {
            String variantId = tag.getString("Variant");
            this.entity.getEntityData().set(
                EntityDamsel.DATA_VARIANT_ID,
                variantId
            );
            this.variant = null; // Invalidate cache
        }

        if (tag.contains("DamselName")) {
            this.setNpcName(tag.getString("DamselName"));
        }

        if (tag.contains("SlimArms")) {
            this.setSlimArms(tag.getBoolean("SlimArms"));
        }

        if (tag.contains("Gender")) {
            String genderName = tag.getString("Gender");
            this.setGender(Gender.fromName(genderName));
        }
    }
}
