package com.tiedup.remake.personality;

import java.util.EnumMap;
import java.util.Map;
import net.minecraft.nbt.CompoundTag;

/**
 * Tracks job experience per NpcCommand type.
 * Experience accumulates as NPCs perform jobs and unlocks efficiency/yield bonuses.
 * Experience accumulates per command type with proficiency tiers.
 */
public class JobExperience {

    /**
     * Job proficiency levels based on accumulated experience.
     */
    public enum JobLevel {
        NOVICE(0, 9, 1.0f, 1.0f, 0),
        APPRENTICE(10, 24, 1.1f, 1.05f, 1),
        SKILLED(25, 49, 1.25f, 1.15f, 2),
        EXPERT(50, Integer.MAX_VALUE, 1.5f, 1.3f, 4);

        public final int minExp;
        public final int maxExp;
        /** Speed multiplier for job actions */
        public final float speedMultiplier;
        /** Yield multiplier for job outputs */
        public final float yieldMultiplier;
        /** Extra work radius bonus (blocks) */
        public final int rangeBonus;

        JobLevel(
            int minExp,
            int maxExp,
            float speedMultiplier,
            float yieldMultiplier,
            int rangeBonus
        ) {
            this.minExp = minExp;
            this.maxExp = maxExp;
            this.speedMultiplier = speedMultiplier;
            this.yieldMultiplier = yieldMultiplier;
            this.rangeBonus = rangeBonus;
        }

        /**
         * Get the job level for a given experience value.
         */
        public static JobLevel fromExperience(int exp) {
            if (exp >= EXPERT.minExp) return EXPERT;
            if (exp >= SKILLED.minExp) return SKILLED;
            if (exp >= APPRENTICE.minExp) return APPRENTICE;
            return NOVICE;
        }
    }

    /** Experience count per job command type. */
    private final Map<NpcCommand, Integer> jobExperience = new EnumMap<>(
        NpcCommand.class
    );

    /**
     * Get experience for a specific job command.
     *
     * @param command The job command
     * @return Experience count (0 if never performed)
     */
    public int getExperience(NpcCommand command) {
        return jobExperience.getOrDefault(command, 0);
    }

    /**
     * Get the job level for a specific command.
     *
     * @param command The job command
     * @return Current JobLevel based on experience
     */
    public JobLevel getJobLevel(NpcCommand command) {
        return JobLevel.fromExperience(getExperience(command));
    }

    /**
     * Add experience for a job command (+1).
     *
     * @param command The job command
     */
    public void addExperience(NpcCommand command) {
        jobExperience.merge(command, 1, Integer::sum);
    }

    /**
     * Get the speed multiplier for a job command based on experience.
     *
     * @param command The job command
     * @return Speed multiplier (1.0 to 1.5)
     */
    public float getSpeedMultiplier(NpcCommand command) {
        return getJobLevel(command).speedMultiplier;
    }

    /**
     * Get the yield multiplier for a job command based on experience.
     *
     * @param command The job command
     * @return Yield multiplier (1.0 to 1.3)
     */
    public float getYieldMultiplier(NpcCommand command) {
        return getJobLevel(command).yieldMultiplier;
    }

    /**
     * Get the range bonus for a job command based on experience.
     *
     * @param command The job command
     * @return Extra radius in blocks (0 to 4)
     */
    public int getRangeBonus(NpcCommand command) {
        return getJobLevel(command).rangeBonus;
    }

    // --- NBT Persistence ---

    public CompoundTag save() {
        CompoundTag tag = new CompoundTag();
        for (Map.Entry<NpcCommand, Integer> entry : jobExperience.entrySet()) {
            tag.putInt(entry.getKey().name(), entry.getValue());
        }
        return tag;
    }

    public static JobExperience load(CompoundTag tag) {
        JobExperience exp = new JobExperience();
        for (NpcCommand cmd : NpcCommand.values()) {
            if (tag.contains(cmd.name())) {
                exp.jobExperience.put(cmd, tag.getInt(cmd.name()));
            }
        }
        return exp;
    }
}
