import { classifyWargearList, splitWargearList } from "./newrecruit-text.js";
const FIRST_LINE = /^(.+)\s-\s\[\s*(\d+)\s*pts?\s*\]\s*$/i;
const ROSTER_HEADER = /^#\s*\+\+\s*Army Roster\s*\+\+\s*\[\s*(\d+)\s*pts?\s*\]\s*$/i;
const SECTION_HEADER = /^##\s*(.+?)(?:\s*\[\s*(\d+)\s*pts?\s*\])?\s*$/;
const UNIT_LINE = /^(.+?)\s*\[\s*(\d+)\s*pts?\s*\](?:\s*:\s*(.*))?$/i;
const BULLET = /^\s*•\s*(\d+)x\s+(.+?)(?:\s*\[\s*(\d+)\s*pts?\s*\])?(?:\s*:\s*(.*))?\s*$/u;
function newUnit(name, displayed_pts) {
    return {
        raw_name: name,
        is_character: false,
        is_warlord: false,
        enhancement_raw_name: null,
        enhancement_pts: 0,
        displayed_pts,
        model_count: 1,
        wargear: new Map(),
    };
}
function addWargear(unit, items) {
    for (const { raw_name, count } of items) {
        unit.wargear.set(raw_name, (unit.wargear.get(raw_name) ?? 0) + count);
    }
}
function applyTokens(unit, tokensCsv, multiplier = 1) {
    const tokens = splitWargearList(tokensCsv);
    const cls = classifyWargearList(tokens);
    if (cls.is_warlord)
        unit.is_warlord = true;
    if (cls.is_character)
        unit.is_character = true;
    if (cls.enhancement_raw_name && unit.enhancement_raw_name === null) {
        unit.enhancement_raw_name = cls.enhancement_raw_name;
        unit.enhancement_pts = cls.enhancement_points ?? 0;
    }
    const scaled = cls.wargear.map((w) => ({
        raw_name: w.raw_name,
        count: w.count * multiplier,
    }));
    addWargear(unit, scaled);
}
function finishUnit(unit) {
    const points = unit.displayed_pts === null ? null : unit.displayed_pts - unit.enhancement_pts;
    return {
        raw_name: unit.raw_name,
        is_character: unit.is_character,
        model_count: unit.model_count,
        points,
        is_warlord: unit.is_warlord,
        enhancement_raw_name: unit.enhancement_raw_name,
        enhancement_points: unit.enhancement_raw_name === null ? null : unit.enhancement_pts,
        wargear: [...unit.wargear].map(([raw_name, count]) => ({ raw_name, count })),
    };
}
function parseFirstLine(line) {
    const m = FIRST_LINE.exec(line);
    if (!m)
        return null;
    const declared_limit = Number.parseInt(m[2], 10);
    const parts = m[1].split(" - ").map((s) => s.trim()).filter((s) => s.length > 0);
    if (parts.length === 0)
        return null;
    const list_name = parts[parts.length - 1];
    const faction = parts.length >= 2 ? parts[parts.length - 2] : null;
    return { name: list_name, faction, declared_limit };
}
export const newRecruitSimpleAdapter = {
    id: "newrecruit-simple",
    matches(decoded) {
        if (typeof decoded !== "string")
            return false;
        const lines = decoded.split(/\r?\n/);
        const firstNonBlank = lines.find((l) => l.trim().length > 0);
        if (!firstNonBlank)
            return false;
        if (!FIRST_LINE.test(firstNonBlank))
            return false;
        return /^#\s*\+\+\s*Army Roster\s*\+\+/m.test(decoded);
    },
    parse(decoded) {
        if (typeof decoded !== "string") {
            throw new Error("newrecruit-simple: input is not a string");
        }
        const lines = decoded.split(/\r?\n/);
        let name = "Imported roster";
        let faction_raw_name = null;
        let declared_limit = null;
        let total_reported = null;
        let detachment_raw_name = null;
        let battle_size_raw = null;
        const units = [];
        let current = null;
        let multi_force = false;
        let section = "preamble";
        const enhancementPts = [];
        const finalize = () => {
            if (current) {
                enhancementPts.push(current.enhancement_pts);
                units.push(finishUnit(current));
                current = null;
            }
        };
        for (let i = 0; i < lines.length; i += 1) {
            const raw = lines[i];
            const line = raw.trim();
            if (!line)
                continue;
            // First non-blank line carries `<breadcrumb> - <faction> - <list> - [N pts]`.
            if (section === "preamble" && name === "Imported roster") {
                const first = parseFirstLine(line);
                if (first) {
                    name = first.name;
                    faction_raw_name = first.faction;
                    declared_limit = first.declared_limit;
                    continue;
                }
            }
            const rosterMatch = ROSTER_HEADER.exec(line);
            if (rosterMatch) {
                total_reported = Number.parseInt(rosterMatch[1], 10);
                continue;
            }
            const sectionMatch = SECTION_HEADER.exec(line);
            if (sectionMatch) {
                finalize();
                const heading = sectionMatch[1].trim().toLowerCase();
                if (heading === "configuration") {
                    section = "configuration";
                }
                else {
                    section = "units";
                    if (heading.includes("allied"))
                        multi_force = true;
                }
                continue;
            }
            if (section === "configuration") {
                const idx = line.indexOf(":");
                if (idx > 0) {
                    const key = line.slice(0, idx).trim().toLowerCase();
                    const value = line.slice(idx + 1).trim();
                    if (key === "battle size")
                        battle_size_raw = value;
                    else if (key === "detachment")
                        detachment_raw_name = value;
                }
                continue;
            }
            // Unit section. A bullet line extends the *current* unit.
            const bulletMatch = BULLET.exec(raw);
            if (bulletMatch && current) {
                const count = Number.parseInt(bulletMatch[1], 10);
                // Bullets may add to the unit's model count beyond the implicit 1 we
                // set when we created it from the unit header.
                if (current.wargear.size === 0 && current.model_count === 1) {
                    // First bullet: replace the implicit single-model assumption.
                    current.model_count = count;
                }
                else {
                    current.model_count += count;
                }
                if (bulletMatch[4])
                    applyTokens(current, bulletMatch[4], count);
                continue;
            }
            const unitMatch = UNIT_LINE.exec(line);
            if (unitMatch) {
                finalize();
                const unitName = unitMatch[1].trim();
                const pts = Number.parseInt(unitMatch[2], 10);
                current = newUnit(unitName, pts);
                const inlineWargear = unitMatch[3]?.trim() ?? "";
                if (inlineWargear.length > 0) {
                    applyTokens(current, inlineWargear, 1);
                }
                // Leave model_count at the default 1. If `•` bullet lines follow, the
                // bullet handler resets model_count to the (summed) bullet counts.
                continue;
            }
        }
        finalize();
        let total_computed = 0;
        for (let i = 0; i < units.length; i += 1) {
            total_computed += units[i].points ?? 0;
            total_computed += enhancementPts[i] ?? 0;
        }
        return {
            name,
            generated_by: null,
            faction_raw_name,
            detachment_raw_name,
            battle_size_raw,
            declared_limit,
            total_reported,
            total_computed,
            units,
            multi_force,
        };
    },
};
//# sourceMappingURL=newrecruit-simple.js.map