package thb.jeanluc.adventure.game;

import thb.jeanluc.adventure.io.text.QuestEntry;
import thb.jeanluc.adventure.io.text.QuestView;
import thb.jeanluc.adventure.io.text.StyledText;
import thb.jeanluc.adventure.model.Quest;
import thb.jeanluc.adventure.model.QuestStage;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/** Per-turn quest progression and view building, driven by world conditions. */
public final class QuestEngine {

    private QuestEngine() {
    }

    public static void tick(GameContext ctx) {
        Map<String, Quest> quests = ctx.getWorld().getQuests();
        for (Quest q : quests.values()) {
            if (q.autoStart() && !ctx.getQuestLog().isActive(q.id()) && !ctx.getQuestLog().isCompleted(q.id())) {
                ctx.getQuestLog().start(q.id());
            }
        }
        int guard = 0;
        int max = totalStages(quests) + quests.size() + 1;
        boolean changed = true;
        while (changed && guard++ < max) {
            changed = false;
            for (String id : new ArrayList<>(ctx.getQuestLog().active())) {
                Quest q = quests.get(id);
                if (q == null) {
                    continue;
                }
                int idx = ctx.getQuestLog().stageIndex(id);
                if (idx >= q.stages().size()) {
                    finish(ctx, q);
                    changed = true;
                    continue;
                }
                QuestStage stage = q.stages().get(idx);
                if (Conditions.all(stage.completion(), ctx)) {
                    Effects.applyAll(stage.onComplete(), ctx);
                    ctx.getIo().print(StyledText.builder()
                            .heading("✓ Objective complete: ").plain(stage.objective()).build());
                    ctx.getQuestLog().advance(id);
                    if (ctx.getQuestLog().stageIndex(id) >= q.stages().size()) {
                        finish(ctx, q);
                    }
                    changed = true;
                }
            }
        }
    }

    private static void finish(GameContext ctx, Quest q) {
        if (ctx.getQuestLog().isCompleted(q.id())) {
            return;
        }
        Effects.applyAll(q.onComplete(), ctx);
        ctx.getQuestLog().complete(q.id());
        ctx.getIo().print(StyledText.builder()
                .heading("★ Quest complete: ").plain(q.title()).build());
        ctx.save();
    }

    public static QuestView viewOf(GameContext ctx) {
        Map<String, Quest> quests = ctx.getWorld().getQuests();
        List<QuestEntry> active = new ArrayList<>();
        for (String id : ctx.getQuestLog().active()) {
            Quest q = quests.get(id);
            if (q == null) {
                continue;
            }
            int idx = ctx.getQuestLog().stageIndex(id);
            String objective = idx < q.stages().size() ? q.stages().get(idx).objective() : "";
            active.add(new QuestEntry(q.title(), objective));
        }
        List<String> completed = new ArrayList<>();
        for (String id : ctx.getQuestLog().completed()) {
            Quest q = quests.get(id);
            completed.add(q == null ? id : q.title());
        }
        return new QuestView(active, completed);
    }

    private static int totalStages(Map<String, Quest> quests) {
        int total = 0;
        for (Quest q : quests.values()) {
            total += q.stages().size();
        }
        return total;
    }
}
