/**
 * Сценарий quest-bells — полный цикл квеста «Три цветка» (акт 1) через мост.
 * 1) Ирвин: elder_first до выбора, вариант по ТЕКСТУ (pickChoiceByText) ->
 *    флаги met_elder + quest_bells_taken;
 * 2) чит-цветы (scene:setVar flowers=3) -> повторный разговор: elder_hand_in
 *    (квест-стадия ready), флаг quest_bells_done, кат-сцена посадки:
 *    vars.flowers -> 0, тост «Поляна гудит», поляна зеленеет;
 * 3) Мила: trader_first (полотно в сумке, met_mila), затем trader_after
 *    (эпилог из квест-стадии);
 * 4) инвариант interact-used-consistent и контент чисты.
 * Запуск: node tools/agent.mjs run tools/checks/quest-bells.mjs
 */
import { startDevServer, openGame, Checks } from '../lib.mjs';

/** Реплика героя в elder_first (выбор по тексту — не по индексу). */
const RING_REPLY = 'Прозвоню дорогу до прудов и вернусь до темноты.';

export default async function ({ pretty }) {
    const c = new Checks('quest-bells');
    const server = await startDevServer();
    let ctx;
    try {
        await c.run('Ирвин: elder_first, выбор по тексту, флаги квеста', async () => {
            ctx = await openGame({ url: server.url, newGame: true });
            await ctx.agent.command('scene:sleepAll');
            await ctx.agent.waitFor('!s.transitioning', { timeoutTicks: 600 });
            // NPC в Звенце: тропа на востоке (26,14), затем Ирвин (12,9).
            const walk = await ctx.agent.walkTo(26, 14, { timeoutTicks: 3000 });
            c.expect(walk, 'не дошёл до тропы в Звенец');
            await ctx.agent.waitFor('s.area === "zvenets"', { timeoutTicks: 600 });
            await ctx.agent.waitFor('!s.transitioning', { timeoutTicks: 600 });
            await ctx.agent.tapTile(12, 9); // Ирвин — клик издалека
            const o = await ctx.agent.waitFor('s.dialogue?.id === "elder_first"', { timeoutTicks: 900 });
            c.expect(o.ok, 'диалог elder_first не открылся', o.snapshot.dialogue);
            // Листаем до выбора: advance при выборе активирует курсор — проверяем снапшот.
            for (let i = 0; i < 12; i++) {
                const s = await ctx.agent.snapshot();
                if (s.dialogue?.waitingForChoice) break;
                if (!s.dialogue) break;
                await ctx.agent.press('advance'); // догнать печать или следующая реплика
            }
            const picked = await ctx.agent.pickChoiceByText(RING_REPLY);
            c.expect(picked, 'вариант по тексту не найден', (await ctx.agent.snapshot()).dialogue);
            const d = await ctx.agent.runDialogue(900);
            c.expect(d, 'диалог не завершился после выбора');
            const w = await ctx.agent.waitFor(
                's.flags.includes("met_elder") && s.flags.includes("quest_bells_taken")',
                { timeoutTicks: 300 }
            );
            c.expect(w.ok, 'граф не поднял флаги знакомства и взятия квеста', w.snapshot.flags);
            return null;
        });
        await c.run('сдача: elder_hand_in, кат-сцена посадки, поляна зеленеет', async () => {
            // Чит-цветы: сам сбор (пруды) покрыт клик-роутингом, здесь — сдача.
            await ctx.agent.command('scene:setVar', { id: 'flowers', value: 3 });
            await ctx.agent.tapTile(12, 9);
            const o = await ctx.agent.waitFor('s.dialogue?.id === "elder_hand_in"', { timeoutTicks: 900 });
            c.expect(o.ok, 'квест-стадия не дала elder_hand_in', o.snapshot.dialogue);
            const d = await ctx.agent.runDialogue(900);
            c.expect(d, 'диалог сдачи не завершился');
            const w = await ctx.agent.waitFor(
                's.flags.includes("quest_bells_done") && s.vars.flowers === 0',
                { timeoutTicks: 900 }
            );
            c.expect(w.ok, 'нет флага сдачи или цветы не списаны', {
                flags: w.snapshot.flags,
                vars: w.snapshot.vars
            });
            // Кат-сцена посадки: тост и конец (клики блокируются до её конца).
            const t = await ctx.agent.waitFor('(s.lastToast?.text ?? "").includes("гудит")', {
                timeoutTicks: 900
            });
            c.expect(t.ok, 'нет тоста посадки', t.snapshot.lastToast);
            await ctx.agent.waitFor('!s.cutscene?.active', { timeoutTicks: 900 });
            return null;
        });
        await c.run('Мила: trader_first (полотно) -> trader_after (эпилог)', async () => {
            await ctx.agent.tapTile(17, 11);
            const o = await ctx.agent.waitFor('s.dialogue?.id === "trader_first"', { timeoutTicks: 900 });
            c.expect(o.ok, 'первый диалог Милы не открылся', o.snapshot.dialogue);
            const d1 = await ctx.agent.runDialogue(900);
            c.expect(d1, 'первый диалог Милы не завершился');
            const inv = await ctx.agent.waitFor(
                '(s.inventory.find((i) => i.id === "cloth")?.count ?? 0) === 1',
                { timeoutTicks: 300 }
            );
            c.expect(inv.ok, 'полотно (do[] giveItem) не в сумке', inv.snapshot.inventory);
            // Повторный разговор: квест-стадия-эпилог -> trader_after.
            await ctx.agent.tapTile(17, 11);
            const o2 = await ctx.agent.waitFor('s.dialogue?.id === "trader_after"', { timeoutTicks: 900 });
            c.expect(o2.ok, 'эпилог trader_after не открылся', o2.snapshot.dialogue);
            const d2 = await ctx.agent.runDialogue(600);
            c.expect(d2, 'эпилог не завершился');
            return null;
        });
        await c.run('инварианты чисты после полного квеста', async () => {
            const inv = await ctx.agent.invariants();
            const bad = inv.filter((i) => i.severity === 'error');
            c.expect(bad.length === 0, 'ошибки инвариантов', bad);
            return null;
        });
    } finally {
        await ctx?.browser?.close();
        server.stop();
    }
    return c.finish({ pretty }).ok ? 0 : 1;
}