package com.tiedup.remake.entities;

import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.skins.Gender;
import com.tiedup.remake.entities.skins.ShinyDamselSkinManager;
import javax.annotation.Nullable;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.level.Level;

/**
 * Shiny Damsel - Rare, faster damsel variant.
 *
 *
 * Differences from regular EntityDamsel:
 * - Much faster movement speed (0.35 vs 0.25)
 * - Rare spawns
 * - Golden/shimmering name color
 * - Dedicated shiny skins
 * - Special sparkle particles
 */
public class EntityDamselShiny extends EntityDamsel {

    // DATA SYNC

    /**
     * Shiny variant name (for skin selection).
     */
    private static final EntityDataAccessor<String> DATA_SHINY_NAME =
        SynchedEntityData.defineId(
            EntityDamselShiny.class,
            EntityDataSerializers.STRING
        );

    // STATE

    @Nullable
    private DamselVariant shinyVariant;

    // CONSTRUCTOR

    public EntityDamselShiny(
        EntityType<? extends EntityDamselShiny> type,
        Level level
    ) {
        super(type, level);
    }

    // ATTRIBUTES

    /**
     * Create shiny damsel attributes.
     * Much faster than regular damsels.
     */
    public static AttributeSupplier.Builder createAttributes() {
        return Mob.createMobAttributes()
            .add(Attributes.MAX_HEALTH, 20.0) // Same health
            .add(Attributes.MOVEMENT_SPEED, 0.35) // Much faster (0.35 vs 0.25)
            .add(Attributes.KNOCKBACK_RESISTANCE, 0.1);
    }

    // DATA SYNC

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.define(DATA_SHINY_NAME, "");
    }

    @Override
    public void onSyncedDataUpdated(EntityDataAccessor<?> key) {
        super.onSyncedDataUpdated(key);
        // Invalidate shiny variant cache when synced from server
        if (DATA_SHINY_NAME.equals(key)) {
            this.shinyVariant = null;
        }
    }

    // INITIALIZATION

    @Override
    public void onAddedToWorld() {
        super.onAddedToWorld();

        // Select deterministic shiny variant based on UUID if not set
        if (
            !this.level().isClientSide && this.getShinyVariantName().isEmpty()
        ) {
            Gender preferredGender = SettingsAccessor.getPreferredSpawnGender(
                this.level().getGameRules()
            );

            DamselVariant variant =
                ShinyDamselSkinManager.CORE.getVariantForEntity(
                    this.getUUID(),
                    preferredGender
                );
            this.setShinyVariant(variant);

            TiedUpMod.LOGGER.info(
                "[EntityDamselShiny] Spawned shiny: {}",
                variant.defaultName()
            );
        }
    }

    // SHINY VARIANT

    /**
     * Get current shiny variant.
     */
    @Nullable
    public DamselVariant getShinyVariant() {
        // Try to load from synced variant name first
        if (
            this.shinyVariant == null && !this.getShinyVariantName().isEmpty()
        ) {
            this.shinyVariant = ShinyDamselSkinManager.CORE.getVariant(
                this.getShinyVariantName()
            );
        }
        // Fallback: compute from UUID if not yet synced (client-side race condition fix)
        if (this.shinyVariant == null) {
            this.shinyVariant = ShinyDamselSkinManager.CORE.getVariantForEntity(
                this.getUUID()
            );
        }
        return this.shinyVariant;
    }

    /**
     * Set shiny variant.
     */
    public void setShinyVariant(DamselVariant variant) {
        if (variant == null) return;

        this.shinyVariant = variant;
        // Bug fix: Store variant.id() for skin lookup, not defaultName()
        this.entityData.set(DATA_SHINY_NAME, variant.id());
        this.setNpcName(variant.defaultName());
        this.setSlimArms(variant.hasSlimArms());
    }

    /**
     * Get shiny variant name (synced data).
     */
    public String getShinyVariantName() {
        return this.entityData.get(DATA_SHINY_NAME);
    }

    /**
     * Get texture for this shiny damsel.
     * Overrides damsel skin system.
     */
    public ResourceLocation getShinySkin() {
        DamselVariant variant = this.getShinyVariant();
        if (variant != null) {
            return variant.texture();
        }
        // Fallback to hardcoded default (don't use getRandomVariant() - causes skin flashing!)
        return ResourceLocation.fromNamespaceAndPath(
            "tiedup",
            "textures/entity/damsel/shiny/ellen.png"
        );
    }

    /**
     * Check if this shiny damsel has slim arms.
     * Uses parent's synced entityData implementation.
     */
    @Override
    public boolean hasSlimArms() {
        return super.hasSlimArms();
    }

    /**
     * Get the skin texture for this shiny damsel.
     * Computes texture path from variant ID - no local skin JSONs needed on client.
     */
    @Override
    public ResourceLocation getSkinTexture() {
        String variantId = this.getShinyVariantName();
        if (!variantId.isEmpty()) {
            return ResourceLocation.fromNamespaceAndPath(
                "tiedup",
                "textures/entity/damsel/shiny/" + variantId + ".png"
            );
        }
        // Fallback
        return ResourceLocation.fromNamespaceAndPath(
            "tiedup",
            "textures/entity/damsel/shiny/ellen.png"
        );
    }

    // DISPLAY

    @Override
    public Component getDisplayName() {
        // Rainbow name: each character gets a different hue
        String name = this.getNpcName();
        net.minecraft.network.chat.MutableComponent result = Component.literal(
            ""
        );
        for (int i = 0; i < name.length(); i++) {
            float hue = (float) i / name.length();
            int rgb = java.awt.Color.HSBtoRGB(hue, 0.9F, 1.0F) & 0xFFFFFF;
            result.append(
                Component.literal(String.valueOf(name.charAt(i))).withStyle(
                    Style.EMPTY.withColor(rgb)
                )
            );
        }
        return result;
    }

    // OVERRIDES

    /**
     * Shiny damsels don't use the standard variant system.
     * They have their own shiny skin system.
     */
    @Override
    public void setVariant(DamselVariant variant) {
        // Don't call super - shiny use their own skin system
        // Name is set in setShinyVariant()
    }

    // NBT PERSISTENCE

    @Override
    public void addAdditionalSaveData(net.minecraft.nbt.CompoundTag tag) {
        super.addAdditionalSaveData(tag);

        // Save shiny variant name
        if (!this.getShinyVariantName().isEmpty()) {
            tag.putString("ShinyVariantName", this.getShinyVariantName());
        }
    }

    @Override
    public void readAdditionalSaveData(net.minecraft.nbt.CompoundTag tag) {
        super.readAdditionalSaveData(tag);

        // Restore shiny variant name
        if (tag.contains("ShinyVariantName")) {
            String variantName = tag.getString("ShinyVariantName");
            this.entityData.set(DATA_SHINY_NAME, variantName);
            // Clear cached variant so it gets reloaded
            this.shinyVariant = null;
        }
    }

    // PARTICLE EFFECTS

    @Override
    public void tick() {
        super.tick();

        // Spawn rainbow sparkle particles (client-side only)
        if (level().isClientSide && this.random.nextFloat() < 0.2F) {
            double x = this.getX() + (this.random.nextDouble() - 0.5) * 0.6;
            double y = this.getY() + this.random.nextDouble() * 1.8;
            double z = this.getZ() + (this.random.nextDouble() - 0.5) * 0.6;

            // Rainbow cycling: hue rotates over time, each particle gets a unique color
            float hue =
                ((this.tickCount * 3 + this.random.nextInt(60)) % 360) / 360.0F;
            int rgb = java.awt.Color.HSBtoRGB(hue, 0.9F, 1.0F);
            float r = ((rgb >> 16) & 0xFF) / 255.0F;
            float g = ((rgb >> 8) & 0xFF) / 255.0F;
            float b = (rgb & 0xFF) / 255.0F;

            net.minecraft.core.particles.DustParticleOptions rainbowDust =
                new net.minecraft.core.particles.DustParticleOptions(
                    new org.joml.Vector3f(r, g, b),
                    0.8F
                );

            this.level().addParticle(rainbowDust, x, y, z, 0.0, 0.02, 0.0);
        }
    }
}
