class Skill extends Initializing implements SkillDefinition{
    id:string;

    label: 'Label Missing';

    hidden: false;

    isDifficultyBased:boolean=false;

    e2s = Skill.e2sFunction();
    s2e = Skill.s2eFunction();

    dailyExpLimit:number|((levelAtStartOfDay:number)=>number)=0;

    //#region Static
        static get(skillId:string):Skill{
            const constantData = setup.skills[skillId];
            if(!constantData)
                return new NullSkill();
            let skill = new Skill();
            skill.init(constantData);
            skill.id = skillId;
            return skill;
        }

        static e2sFunction(factorEvery10Levels=2,factor=100){
            return function(n:number){
                const base = factorEvery10Levels ** 0.1;
                n += factor;
                return Math.floor(Math.logBase(n/100,base));
            }
        }

        static s2eFunction(factorEvery10Levels=2,factor=100){
            return function(n:number):number{
                const base = factorEvery10Levels ** 0.1;
                return Math.ceil(Math.pow(base,n) * factor) - factor;
            }
        }
    //#endregion

    experience2Skill(experience:number){return this.e2s(experience);}
    skill2Experience(skillLevel:number){return this.s2e(skillLevel);}

    
    get dailyExperienceSoftLimit():((levelAtStartOfDay:number)=>number){
        if(this.dailyExpLimit){
            if(typeof this.dailyExpLimit == "number"){
                const number = this.dailyExpLimit;
                return (n=>number);
            }
            return this.dailyExpLimit;
        }
        return (n=>this.skill2Experience(n + 1) - this.skill2Experience(n));
    }

    /**
     * How much experiences to gain depending on the experience already received today.
     * @param {SkillOfCharacter} skillData
     * @param {number} requestedExperienceIncrease
     * @returns {number}
     */
    skillGain(skillData: SkillOfCharacter, requestedExperienceIncrease:number):number{
        let experienceEffectiveGain = 0;
        const todaysStartExperience = skillData.experienceHistory.last();
        const todaysStartLevel = this.experience2Skill(todaysStartExperience);
        //const experienceRequiredToAdvanceOneLevel = this.skill2Experience(todaysStartLevel + 1) - this.skill2Experience(todaysStartLevel);
        const experienceWithoutPenalty = this.dailyExperienceSoftLimit(todaysStartLevel);

        let experienceGainedSoFarToday = skillData.experience - todaysStartExperience;
        const experienceToGainWithoutPenaltyLeft = Math.max(0,experienceWithoutPenalty - experienceGainedSoFarToday);

        const experienceToGainWithoutPenalty = Math.min(requestedExperienceIncrease,experienceToGainWithoutPenaltyLeft);
        experienceEffectiveGain += experienceToGainWithoutPenalty;
        experienceGainedSoFarToday += experienceToGainWithoutPenalty;
        requestedExperienceIncrease -= experienceToGainWithoutPenalty;

        const requestedTotalExperienceIncrease = experienceGainedSoFarToday + requestedExperienceIncrease;
        const factorOfBeingOverTarget = requestedTotalExperienceIncrease / experienceWithoutPenalty;

        const experienceGainWithPenalty = Math.ceil(requestedExperienceIncrease / factorOfBeingOverTarget);

        experienceEffectiveGain += experienceGainWithPenalty;

        return experienceEffectiveGain;
    }
}

class NullSkill extends Skill{

}

setup.Skill = Skill;

setup.skills = {};

setup.skills.agility = {
    label: 'Agility',
    hidden: true
}

setup.skills.charisma = {
    label: 'Charisma',
    hidden: true
}

setup.skills.chess = {
    label: 'Chess',
    e2s: Skill.e2sFunction(2.5),
    s2e: Skill.s2eFunction(2.5),
    image:'pc/skills/chess.webp'
}

setup.skills.computer = {
    label: 'Computer',
    image:'pc/skills/computer.webp'
}

setup.skills.dance = {
    label: 'Dancing',
    image:'pc/skills/dance.webp'
}

setup.skills.gaming = {
    label: 'Gaming',
    e2s: Skill.e2sFunction(1.5),
    s2e: Skill.s2eFunction(1.5),
    image:'pc/skills/gaming.webp'
}

setup.skills.gunnery = {
    label: 'Shooting (Gun)',
    e2s: Skill.e2sFunction(1.5),
    s2e: Skill.s2eFunction(1.5),
    image:'pc/skills/gunnery.webp'
}

setup.skills.iceskating = {
    label: 'Iceskating',
    hidden: true
}

setup.skills.inhibition = {
    label: 'Inhibition'
}

setup.skills.intelligence = {
    label: 'Intelligence',
    hidden: true
}

setup.skills.people = {
    label: 'People',
    hidden: true
}

setup.skills.perception = {
    label: 'Perception',
    hidden: true
}

setup.skills.persuasion = {
    label: 'Persuasion',
    hidden: true
}

setup.skills.reaction = {
    label: 'Reaction',
    hidden: true
}

setup.skills.spirit = {
    label: 'Spirit',
    hidden: true
}

setup.skills.strength = {
    label: 'Strength',
    hidden: true
}

setup.skills.vitality = {
    label: 'Vitality',
    hidden: true
}

setup.skills.webcam = {
    label: 'Webcam Girl',
    e2s: Skill.e2sFunction(1.5),
    s2e: Skill.s2eFunction(1.5)
}