import { EventBus } from '../core/EventBus.js';

/* ────────────────────────────────────────────────────────────────
   Tutorial Branching & Achievement System — LEGENDARY L4
   
   • Conditional branching (step → step based on quiz results / choices)
   • Achievement / badge engine tied to tutorial completions
   • Progress-based unlocking logic
──────────────────────────────────────────────────────────────── */
class BranchingEngine {
    constructor() {
        this.configs = new Map();
    }
    /** Register branching configuration for a tutorial. */
    register(config) {
        const stepMap = new Map();
        for (const branch of config.branches) {
            stepMap.set(branch.stepId, branch);
        }
        this.configs.set(config.tutorialId, stepMap);
    }
    /** Unregister branching for a tutorial. */
    unregister(tutorialId) {
        this.configs.delete(tutorialId);
    }
    /** Check if a step has branching rules. */
    hasBranching(tutorialId, stepId) {
        const map = this.configs.get(tutorialId);
        return map ? map.has(stepId) : false;
    }
    /**
     * Resolve the next step ID based on branching rules and context.
     * Returns null if no branching is defined (use default sequential advance).
     */
    resolveNextStep(tutorialId, currentStepId, context) {
        var _a;
        const map = this.configs.get(tutorialId);
        if (!map)
            return null;
        const branch = map.get(currentStepId);
        if (!branch)
            return null;
        for (const rule of branch.rules) {
            if (this.evaluateCondition(rule.condition, context)) {
                return rule.targetStepId;
            }
        }
        return (_a = branch.fallbackStepId) !== null && _a !== void 0 ? _a : null;
    }
    evaluateCondition(condition, ctx) {
        switch (condition.type) {
            case 'quiz-correct':
                return ctx.quizCorrect === true;
            case 'quiz-incorrect':
                return ctx.quizCorrect === false;
            case 'quiz-answer':
                return ctx.quizAnswerId === condition.answerId;
            case 'code-valid':
                return ctx.codeValid === true;
            case 'code-invalid':
                return ctx.codeValid === false;
            case 'always':
                return true;
            default:
                return false;
        }
    }
}
class AchievementEngine {
    constructor(persistToStorage = true) {
        this.persistToStorage = persistToStorage;
        this.events = new EventBus();
        this.definitions = new Map();
        this.playerProgress = new Map();
        this.customEvaluators = new Map();
        this.storageKey = 'nice2dev_achievements';
        if (this.persistToStorage)
            this.load();
    }
    /* ── Registration ───────────────────────────────────────────── */
    /** Register an achievement definition. */
    registerAchievement(def) {
        this.definitions.set(def.id, def);
        if (!this.playerProgress.has(def.id)) {
            this.playerProgress.set(def.id, {
                achievementId: def.id,
                unlocked: false,
                progress: 0,
            });
        }
    }
    /** Register multiple achievements. */
    registerAchievements(defs) {
        for (const d of defs)
            this.registerAchievement(d);
    }
    /** Register a custom evaluator for custom conditions. */
    registerCustomEvaluator(customId, evaluator) {
        this.customEvaluators.set(customId, evaluator);
    }
    /* ── Evaluation ─────────────────────────────────────────────── */
    /**
     * Evaluate all achievements against current tutorial progress.
     * Returns newly unlocked achievement IDs.
     */
    evaluate(tutorialProgress, streakDays = 0) {
        const newlyUnlocked = [];
        for (const [id, def] of this.definitions) {
            const prog = this.playerProgress.get(id);
            if (!prog || prog.unlocked)
                continue;
            const result = this.evaluateCondition(def.condition, tutorialProgress, streakDays);
            prog.progress = result.progress;
            if (result.met && !prog.unlocked) {
                prog.unlocked = true;
                prog.unlockedAt = Date.now();
                newlyUnlocked.push(id);
                this.events.emit('achievement:unlocked', {
                    achievementId: id,
                    definition: def,
                    xp: def.xp,
                });
            }
        }
        if (newlyUnlocked.length > 0)
            this.save();
        return newlyUnlocked;
    }
    evaluateCondition(cond, progress, streakDays) {
        var _a, _b;
        switch (cond.type) {
            case 'tutorial-complete': {
                if (!cond.tutorialId)
                    return { met: false, progress: 0 };
                const tp = progress.get(cond.tutorialId);
                return { met: (tp === null || tp === void 0 ? void 0 : tp.completed) === true, progress: (tp === null || tp === void 0 ? void 0 : tp.completed) ? 1 : 0 };
            }
            case 'tutorials-count': {
                const target = (_a = cond.count) !== null && _a !== void 0 ? _a : 1;
                let completed = 0;
                for (const p of progress.values()) {
                    if (p.completed)
                        completed++;
                }
                return { met: completed >= target, progress: Math.min(1, completed / target) };
            }
            case 'category-complete': {
                // All tutorials in a category — checked via custom evaluator since
                // we don't have the tutorial definitions here
                const evaluator = cond.category ? this.customEvaluators.get(`category:${cond.category}`) : undefined;
                if (evaluator)
                    return evaluator();
                return { met: false, progress: 0 };
            }
            case 'streak': {
                const target = (_b = cond.streakDays) !== null && _b !== void 0 ? _b : 1;
                return { met: streakDays >= target, progress: Math.min(1, streakDays / target) };
            }
            case 'quiz-perfect': {
                // All quizzes answered correctly
                let totalQuizzes = 0;
                let perfectQuizzes = 0;
                for (const p of progress.values()) {
                    for (const correct of Object.values(p.quizScores)) {
                        totalQuizzes++;
                        if (correct)
                            perfectQuizzes++;
                    }
                }
                if (totalQuizzes === 0)
                    return { met: false, progress: 0 };
                const ratio = perfectQuizzes / totalQuizzes;
                return { met: ratio >= 1, progress: ratio };
            }
            case 'custom': {
                if (!cond.customId)
                    return { met: false, progress: 0 };
                const evaluator = this.customEvaluators.get(cond.customId);
                if (evaluator)
                    return evaluator();
                return { met: false, progress: 0 };
            }
            default:
                return { met: false, progress: 0 };
        }
    }
    /* ── Queries ────────────────────────────────────────────────── */
    /** Get all achievement definitions. */
    getAllAchievements() {
        return Array.from(this.definitions.values());
    }
    /** Get unlocked achievements. */
    getUnlocked() {
        const result = [];
        for (const [id, prog] of this.playerProgress) {
            if (prog.unlocked) {
                const def = this.definitions.get(id);
                if (def)
                    result.push(def);
            }
        }
        return result;
    }
    /** Get progress for a specific achievement. */
    getProgress(achievementId) {
        return this.playerProgress.get(achievementId);
    }
    /** Total XP from unlocked achievements. */
    getTotalXP() {
        let xp = 0;
        for (const [id, prog] of this.playerProgress) {
            if (prog.unlocked) {
                const def = this.definitions.get(id);
                if (def)
                    xp += def.xp;
            }
        }
        return xp;
    }
    /** Get visible achievements (not hidden, or hidden but unlocked). */
    getVisible(locale = 'en') {
        var _a, _b;
        const result = [];
        for (const [id, def] of this.definitions) {
            const prog = this.playerProgress.get(id);
            const unlocked = (_a = prog === null || prog === void 0 ? void 0 : prog.unlocked) !== null && _a !== void 0 ? _a : false;
            if (def.hidden && !unlocked)
                continue;
            result.push({
                ...def,
                unlocked,
                progress: (_b = prog === null || prog === void 0 ? void 0 : prog.progress) !== null && _b !== void 0 ? _b : 0,
            });
        }
        return result;
    }
    /** Reset all progress. */
    reset() {
        for (const prog of this.playerProgress.values()) {
            prog.unlocked = false;
            prog.unlockedAt = undefined;
            prog.progress = 0;
        }
        this.save();
    }
    /* ── Persistence ────────────────────────────────────────────── */
    save() {
        if (!this.persistToStorage)
            return;
        try {
            const data = {};
            for (const [id, prog] of this.playerProgress) {
                data[id] = prog;
            }
            localStorage.setItem(this.storageKey, JSON.stringify(data));
        }
        catch ( /* storage unavailable */_a) { /* storage unavailable */ }
    }
    load() {
        try {
            const raw = localStorage.getItem(this.storageKey);
            if (!raw)
                return;
            const data = JSON.parse(raw);
            for (const [id, prog] of Object.entries(data)) {
                this.playerProgress.set(id, prog);
            }
        }
        catch ( /* ignore */_a) { /* ignore */ }
    }
}
/* ══════════════════════════════════════════════════════════════
   Built-in Achievement Definitions
   ══════════════════════════════════════════════════════════════ */
const BUILT_IN_ACHIEVEMENTS = [
    {
        id: 'first-tutorial',
        title: { en: 'First Steps', pl: 'Pierwsze kroki', de: 'Erste Schritte' },
        description: { en: 'Complete your first tutorial', pl: 'Ukończ swój pierwszy tutorial', de: 'Schließe dein erstes Tutorial ab' },
        icon: '🎉',
        tier: 'bronze',
        xp: 10,
        condition: { type: 'tutorials-count', count: 1 },
    },
    {
        id: 'five-tutorials',
        title: { en: 'Getting Serious', pl: 'Robi się poważnie', de: 'Es wird ernst' },
        description: { en: 'Complete 5 tutorials', pl: 'Ukończ 5 tutoriali', de: 'Schließe 5 Tutorials ab' },
        icon: '📚',
        tier: 'silver',
        xp: 50,
        condition: { type: 'tutorials-count', count: 5 },
    },
    {
        id: 'ten-tutorials',
        title: { en: 'Tutorial Master', pl: 'Mistrz tutoriali', de: 'Tutorial-Meister' },
        description: { en: 'Complete 10 tutorials', pl: 'Ukończ 10 tutoriali', de: 'Schließe 10 Tutorials ab' },
        icon: '🏅',
        tier: 'gold',
        xp: 100,
        condition: { type: 'tutorials-count', count: 10 },
    },
    {
        id: 'all-fifteen',
        title: { en: 'Legend', pl: 'Legenda', de: 'Legende' },
        description: { en: 'Complete all 15 game engine tutorials', pl: 'Ukończ wszystkie 15 tutoriali game engine', de: 'Schließe alle 15 Game-Engine-Tutorials ab' },
        icon: '👑',
        tier: 'diamond',
        xp: 500,
        condition: { type: 'tutorials-count', count: 15 },
    },
    {
        id: 'first-game',
        title: { en: 'Game Creator', pl: 'Twórca gier', de: 'Spieleentwickler' },
        description: { en: 'Complete the "Build a Platformer" tutorial', pl: 'Ukończ tutorial "Zrób platformera"', de: 'Schließe das "Build a Platformer" Tutorial ab' },
        icon: '🎮',
        tier: 'gold',
        xp: 75,
        condition: { type: 'tutorial-complete', tutorialId: 'build-a-platformer' },
    },
    {
        id: 'rpg-master',
        title: { en: 'RPG Architect', pl: 'Architekt RPG', de: 'RPG-Architekt' },
        description: { en: 'Complete the "Build an RPG" tutorial', pl: 'Ukończ tutorial "Zrób RPG"', de: 'Schließe das "Build an RPG" Tutorial ab' },
        icon: '⚔️',
        tier: 'gold',
        xp: 75,
        condition: { type: 'tutorial-complete', tutorialId: 'build-an-rpg' },
    },
    {
        id: 'quiz-ace',
        title: { en: 'Quiz Ace', pl: 'As quizów', de: 'Quiz-Ass' },
        description: { en: 'Answer all quiz questions correctly', pl: 'Odpowiedz poprawnie na wszystkie quizy', de: 'Beantworte alle Quizfragen richtig' },
        icon: '🧠',
        tier: 'platinum',
        xp: 200,
        condition: { type: 'quiz-perfect' },
    },
    {
        id: 'publisher',
        title: { en: 'Publisher', pl: 'Wydawca', de: 'Publisher' },
        description: { en: 'Complete the "Publish Your Game" tutorial', pl: 'Ukończ tutorial "Publikacja gry"', de: 'Schließe das "Publish Your Game" Tutorial ab' },
        icon: '🚀',
        tier: 'silver',
        xp: 50,
        condition: { type: 'tutorial-complete', tutorialId: 'publish-your-game' },
    },
    {
        id: 'week-streak',
        title: { en: 'Dedicated', pl: 'Oddany', de: 'Engagiert' },
        description: { en: 'Study for 7 consecutive days', pl: 'Ucz się przez 7 kolejnych dni', de: 'Lerne 7 Tage am Stück' },
        icon: '🔥',
        tier: 'silver',
        xp: 50,
        condition: { type: 'streak', streakDays: 7 },
    },
    {
        id: 'month-streak',
        title: { en: 'Unstoppable', pl: 'Niepokonany', de: 'Unaufhaltsam' },
        description: { en: 'Study for 30 consecutive days', pl: 'Ucz się przez 30 kolejnych dni', de: 'Lerne 30 Tage am Stück' },
        icon: '💎',
        tier: 'diamond',
        xp: 300,
        condition: { type: 'streak', streakDays: 30 },
        hidden: true,
    },
    {
        id: '3d-pioneer',
        title: { en: '3D Pioneer', pl: 'Pionier 3D', de: '3D-Pionier' },
        description: { en: 'Complete the "Build a 3D Game" tutorial', pl: 'Ukończ tutorial "Zrób grę 3D"', de: 'Schließe das "3D-Spiel bauen" Tutorial ab' },
        icon: '🌐',
        tier: 'gold',
        xp: 75,
        condition: { type: 'tutorial-complete', tutorialId: 'build-a-3d-game' },
    },
    {
        id: 'multiplayer-hero',
        title: { en: 'Multiplayer Hero', pl: 'Bohater multiplayera', de: 'Multiplayer-Held' },
        description: { en: 'Complete the online multiplayer tutorial', pl: 'Ukończ tutorial multiplayer online', de: 'Schließe das Online-Multiplayer-Tutorial ab' },
        icon: '🌍',
        tier: 'gold',
        xp: 75,
        condition: { type: 'tutorial-complete', tutorialId: 'multiplayer-online-webrtc' },
    },
];

export { AchievementEngine, BUILT_IN_ACHIEVEMENTS, BranchingEngine };
//# sourceMappingURL=TutorialBranching.js.map
