// Brass and Sigil -- /bns sell shop (Phase 1 of the economy)
//
// Players sell raw commodities to "the Bazaar" for spurs. Implementation:
//   - Command-driven for now: /bns sell <item> [count]
//   - When the bnstoolkit mod ships, a Numismatics shop block in the
//     Merchant's Bazaar will call the same backend.
//
// Mechanics per docs/economy-system.md §11.4:
//   - Base price per item is configured below in SELL_PRICES
//   - Bazaar charges a base 25% fee, reduced by the player's tier
//     discount (read from player.persistentData.bnsTier).
//   - Diminishing returns: each player has a per-item lifetime-sales
//     counter. Price reduces 10% per 64 sold, floored at 50% of base.
//
// Storage:
//   player.persistentData.bnsSales -- compound map: item_id -> int count

// ─── Sell catalogue ─────────────────────────────────────────────────
// Add/remove items here. Prices are pre-fee, pre-DR — "list price."
const SELL_PRICES = {
    'minecraft:diamond':         10,
    'minecraft:netherite_ingot': 100,
    'minecraft:emerald':         1,
    'minecraft:gold_ingot':      2,
    'minecraft:iron_ingot':      1,   // small unit value; sell in stacks
    'minecraft:lapis_lazuli':    1,
    'minecraft:redstone':        1,
    'minecraft:coal':            1,   // 4 coal = 1 spur after DR + fee
    'minecraft:ancient_debris':  500, // raw, rare
};

// Constants like BAZAAR_BASE_FEE_PCT live in 00_tier_system.js.
// Coin handling (COIN_VALUES, DENOMS_DESC, giveCoins) lives in plots.js.
// All top-level `const`/`function` declarations are in the shared
// Rhino global scope, so we just call them directly here.

const DR_STEP = 64;     // every N sold => price drops a step
const DR_DECAY = 0.10;  // 10% drop per step
const DR_FLOOR = 0.50;  // never below 50% of base

// ─── Sales tracker ─────────────────────────────────────────────────
function getSalesMap(player) {
    const data = player.persistentData;
    if (!data.contains('bnsSales')) {
        data.put('bnsSales', {});
    }
    return data.getCompound('bnsSales');
}

function lifetimeSold(player, itemId) {
    const map = getSalesMap(player);
    return map.contains(itemId) ? map.getInt(itemId) : 0;
}

function recordSale(player, itemId, count) {
    const map = getSalesMap(player);
    const prev = map.contains(itemId) ? map.getInt(itemId) : 0;
    map.putInt(itemId, prev + count);
}

// ─── Pricing ───────────────────────────────────────────────────────
// Effective per-unit payout for the player after DR + fee.
// Worked example for a Peasant selling their first diamond:
//   base = 10
//   DR multiplier = max(0.50, 1 - 0 * 0.10) = 1.0
//   pre-fee per unit = 10
//   tier discount = 0, effective fee = 25%
//   payout = floor(10 * 0.75) = 7
function effectivePayout(player, itemId, count) {
    const base = SELL_PRICES[itemId];
    if (!base) return 0;

    const sold = lifetimeSold(player, itemId);
    // average DR multiplier across the units being sold this transaction.
    // Approximated by midpoint of the range.
    const midSteps = Math.floor((sold + count / 2) / DR_STEP);
    const drMult = Math.max(DR_FLOOR, 1 - midSteps * DR_DECAY);

    const feePct = bnsTier.effectiveShopFeePct(player);
    const grossPerUnit = base * drMult;
    const netPerUnit = grossPerUnit * (1 - feePct / 100);

    return Math.floor(netPerUnit * count);
}

// Display-only single-unit price (for /bns sell list)
function singleUnitPriceDisplay(player, itemId) {
    const base = SELL_PRICES[itemId];
    if (!base) return '-';
    const sold = lifetimeSold(player, itemId);
    const steps = Math.floor(sold / DR_STEP);
    const drMult = Math.max(DR_FLOOR, 1 - steps * DR_DECAY);
    const feePct = bnsTier.effectiveShopFeePct(player);
    const net = base * drMult * (1 - feePct / 100);
    return Math.floor(net).toString();
}

// ─── Inventory helpers ─────────────────────────────────────────────
function takeFromInventory(player, itemId, count) {
    let remaining = count;
    const inv = player.inventory;
    for (let i = 0; i < inv.containerSize && remaining > 0; i++) {
        const stack = inv.getItem(i);
        if (stack.id !== itemId) continue;
        const take = Math.min(stack.count, remaining);
        stack.shrink(take);
        remaining -= take;
    }
    return count - remaining; // how many were actually taken
}

function countInInventory(player, itemId) {
    let total = 0;
    const inv = player.inventory;
    for (let i = 0; i < inv.containerSize; i++) {
        const stack = inv.getItem(i);
        if (stack.id === itemId) total += stack.count;
    }
    return total;
}

// ─── Commands ──────────────────────────────────────────────────────
ServerEvents.commandRegistry(event => {
    const { commands: Commands, arguments: Arguments } = event;

    const sellCmd = Commands.literal('bns')
        .then(Commands.literal('sell')

            // /bns sell list
            .then(Commands.literal('list').executes(ctx => {
                const player = ctx.source.player;
                if (!player) { ctx.source.sendSystemMessage(Text.red('Run from a player context.')); return 0; }
                const feeNow = bnsTier.effectiveShopFeePct(player);
                ctx.source.sendSystemMessage(Text.aqua(`--- Bazaar sell prices (your effective fee: ${feeNow}%) ---`));
                for (const itemId of Object.keys(SELL_PRICES)) {
                    const base = SELL_PRICES[itemId];
                    const now = singleUnitPriceDisplay(player, itemId);
                    const sold = lifetimeSold(player, itemId);
                    ctx.source.sendSystemMessage(Text.gray(
                        `  ${itemId}  base ${base}  -> you get ${now}  (you've sold ${sold})`
                    ));
                }
                ctx.source.sendSystemMessage(Text.gray('Sell: /bns sell <item-id> [count]  (omit count to sell 1)'));
                return 1;
            }))

            // /bns sell <item-id> [count]
            .then(Commands.argument('item', Arguments.STRING.create(event))
                .executes(ctx => {
                    return doSell(ctx, Arguments.STRING.getResult(ctx, 'item'), 1);
                })
                .then(Commands.argument('count', Arguments.INTEGER.create(event))
                    .executes(ctx => {
                        const item = Arguments.STRING.getResult(ctx, 'item');
                        const count = Arguments.INTEGER.getResult(ctx, 'count');
                        return doSell(ctx, item, count);
                    })))
        );

    event.register(sellCmd);
});

function doSell(ctx, itemId, count) {
    const player = ctx.source.player;
    if (!player) { ctx.source.sendSystemMessage(Text.red('Run from a player context.')); return 0; }
    if (!SELL_PRICES[itemId]) {
        player.tell(Text.red(`The Bazaar doesn't buy '${itemId}'. Try /bns sell list.`));
        return 0;
    }
    if (count < 1) {
        player.tell(Text.red('Count must be at least 1.'));
        return 0;
    }
    const have = countInInventory(player, itemId);
    if (have < count) {
        player.tell(Text.red(`You only have ${have}x ${itemId} (need ${count}).`));
        return 0;
    }
    const payout = effectivePayout(player, itemId, count);
    if (payout <= 0) {
        player.tell(Text.red(`Payout would be 0 spurs (DR + fee). Wait or upgrade your tier.`));
        return 0;
    }
    const taken = takeFromInventory(player, itemId, count);
    if (taken !== count) {
        // Defensive: shouldn't happen — countInInventory said we had enough
        player.tell(Text.red(`Failed to remove ${count}x ${itemId} (took ${taken}). Aborting.`));
        return 0;
    }
    recordSale(player, itemId, count);
    giveCoins(player, payout);  // shared from plots.js
    player.tell(Text.gold(`Sold ${count}x ${itemId} for ${payout} spurs.`));
    console.info(`[bns/sell] ${player.username} sold ${count}x ${itemId} for ${payout} spurs (lifetime ${lifetimeSold(player, itemId)})`);
    return 1;
}

console.info('[bns/sell_shop] loaded — 9 items in catalogue, DR + tier-fee active');
