/**
 * Квест «Три цветка» (перенос v1 FlowerQuest на воксельный мир): сбор
 * лунных колокольчиков у прудов, посадка поляны у тропы Звенца с
 * пересевом на соседние тайлы. Изменения тайлов — правки вокселя цветка
 * + журнал правок (переживает пересборку мира при переходе областей).
 */
import type { VoxelWorld } from '@rpg/engine';
import { GROUND_Y, UNIT, type AreaLayout } from './areas';
import { QUEST_FLOWERS, QUEST_PLANT_TILES, QUEST_TOWER_GREEN, QUEST_TOWER_TILE } from './data/quests';
import { VARS } from './data/ids';
import type { GameState } from './state';

/** Тайл раскладки v1: цветок / трава / пепел. */
const T_BELLFLOWER = 5, T_GRASS = 0, T_ASH = 4;
/** Слот вокселя цветка (B1 — тёплая жизнь). */
const FLOWER = 9;

/** Воксель цветка тайла (центр, как stampBellflower в areas.ts). */
function flowerVoxel(tx: number, ty: number): [number, number, number] {
    return [tx * UNIT + 1, GROUND_Y, ty * UNIT + 1];
}

/** Правки цветков области: тайл → стоит ли цветок (переживает пересборку). */
export type FlowerEdits = Map<string, Map<number, boolean>>;

/** Тайлы раскладки области (RLE → плоский массив). */
function tilesOf(l: AreaLayout): number[] {
    const out: number[] = [];
    for (const [id, run] of l.tiles) for (let k = 0; k < run; k++) out.push(id);
    while (out.length < l.width * l.height) out.push(T_ASH);
    return out;
}

/** Тайтл цветка: тайл раскладки — сборный и правка не снята. */
export class FlowerQuest {
    /** Правки по областям: areaId → (индекс тайла → стоит ли цветок). */
    readonly edits: FlowerEdits = new Map();
    /** Кэш декодированных тайлов текущей раскладки (isFlower зовётся ~25 раз/тик). */
    private tilesCache: { layout: AreaLayout; flat: number[] } | null = null;

    constructor(
        private state: GameState,
        /** Взять воксельный мир текущей области (он пересоздаётся на переходах). */
        private world: () => VoxelWorld,
        private layout: () => AreaLayout,
        private areaId: () => string,
        private showToast: (text: string) => void,
        /** Собранный цветок — в сумку (v1: inventory.add('bellflower')). */
        private addItem: (id: string) => void = () => {},
        /** Правка тайла поля (v1 setTileTracked): свет колокольчиков следует за полем. */
        private onFlowerTile?: (tx: number, ty: number, present: boolean) => void,
    ) {}

    /** Тайлы раскладки с кэшем (кэш живёт, пока жива ссылка на раскладку). */
    private flatTiles(l: AreaLayout): number[] {
        if (this.tilesCache?.layout !== l) this.tilesCache = { layout: l, flat: tilesOf(l) };
        return this.tilesCache.flat;
    }

    /** Цветок стоит на тайле? (раскладка + правки) */
    isFlower(tx: number, ty: number): boolean {
        const l = this.layout();
        if (tx < 0 || ty < 0 || tx >= l.width || ty >= l.height) return false;
        const idx = ty * l.width + tx;
        const edit = this.edits.get(this.areaId())?.get(idx);
        if (edit !== undefined) return edit;
        return this.flatTiles(l)[idx] === T_BELLFLOWER;
    }

    /** Записать правку тайла (стоит/не стоит цветок). */
    private setFlower(tx: number, ty: number, present: boolean): void {
        let per = this.edits.get(this.areaId());
        if (!per) this.edits.set(this.areaId(), (per = new Map()));
        per.set(ty * this.layout().width + tx, present);
        const [x, y, z] = flowerVoxel(tx, ty);
        this.world().set(x, y, z, present ? FLOWER : 0);
        this.onFlowerTile?.(tx, ty, present);
    }

    /** Восстановить цветки области после пересборки мира. */
    restore(): void {
        const per = this.edits.get(this.areaId());
        if (!per) return;
        for (const [idx, present] of per) {
            const [x, y, z] = flowerVoxel(idx % this.layout().width, Math.floor(idx / this.layout().width));
            this.world().set(x, y, z, present ? FLOWER : 0);
        }
    }

    /** Сбор лунного колокольчика: цветок — в сумку, прогресс — в vars. */
    collect(tx: number, ty: number): void {
        this.setFlower(tx, ty, false);
        this.addItem('bellflower'); // v1: предмет виден в сумке до сдачи
        this.state.setVar(VARS.flowers, this.state.getNumber(VARS.flowers) + 1);
        const n = this.state.getNumber(VARS.flowers);
        this.showToast(`Лунный колокольчик (${Math.min(n, QUEST_FLOWERS)}/${QUEST_FLOWERS})`);
    }

    /** Посадка: поляна у тропы гудит и расползается на соседние тайлы. */
    plantFlowers(): void {
        const left = this.state.getNumber(VARS.flowers) - QUEST_FLOWERS;
        this.state.setVar(VARS.flowers, Math.max(0, left));
        for (const [tx, ty] of QUEST_PLANT_TILES) this.setFlower(tx, ty, true);
        // Пересев: поляна расползается на соседние тайлы (якорь «надежда растёт»).
        const l = this.layout();
        const tiles = this.flatTiles(l);
        for (const [tx, ty] of QUEST_PLANT_TILES) {
            for (const [dx, dy] of [[1, 0], [-1, 0], [0, 1], [0, -1]] as const) {
                const x = tx + dx, y = ty + dy;
                const t = tiles[y * l.width + x];
                if ((t === T_GRASS || t === T_ASH) && !this.isFlower(x, y)) this.setFlower(x, y, true);
            }
        }
        this.showToast('Цветы в земле. Поляна гудит.');
    }

    /** Зелень у подножия башни: визуальный финал акта 1. */
    raiseTowerGreen(): void {
        const l = this.layout();
        const tiles = this.flatTiles(l);
        for (const [tx, ty] of QUEST_TOWER_GREEN) {
            const t = tiles[ty * l.width + tx];
            if ((t === T_GRASS || t === T_ASH) && !this.isFlower(tx, ty)) this.setFlower(tx, ty, true);
        }
    }

    /** Тайл башни Звенца (камера кат-сцены сдачи идёт сюда). */
    get towerTile(): { x: number; y: number } {
        return QUEST_TOWER_TILE;
    }
}