import { TradeGoodsCatalog } from "./TradeGoodsCatalog.js";
import { TradeBasinEconomyService } from "./TradeBasinEconomyService.js";
import { SettlementMarketplaceModel } from "../models/SettlementMarketplaceModel.js";

export class SettlementMarketplaceInventoryService {
    static async create({ entity = {}, shop = {}, economy = null, rules = null, seed = "", providerId = "" } = {}) {
        const goods = await TradeGoodsCatalog.getGoodsForLocation(entity);
        const economyState = economy || SettlementMarketplaceModel.getEconomy(entity);
        const marketRules = rules || SettlementMarketplaceModel.getRules(shop, entity);
        const producedIds = this.#ids(economyState.produces);
        const goodsById = new Map(goods.map(good => [good.id, good]));
        const random = this.#createRandom(String(seed || foundry.utils.randomID()));
        const localIds = producedIds.filter(id => goodsById.has(id));
        const localSet = new Set(localIds);
        const marketState = TradeBasinEconomyService.getMarketState(entity);
        const basin = marketState.basin;
        const regionalCandidates = [...(basin?.goods || [])]
            .filter(id => {
                if (!goodsById.has(id) || localSet.has(id)) return false;
                const producers = basin?.producersByGoodId?.get(id) || [];
                return producers.some(producer => producer.entityId !== entity?.id);
            })
            .sort((left, right) => left.localeCompare(right));
        for (let index = regionalCandidates.length - 1; index > 0; index--) {
            const swapIndex = Math.floor(random() * (index + 1));
            [regionalCandidates[index], regionalCandidates[swapIndex]] = [regionalCandidates[swapIndex], regionalCandidates[index]];
        }
        const regionalIds = regionalCandidates.slice(0, marketRules.regionalVariety);
        const selectedIds = [...localIds, ...regionalIds];
        return selectedIds.map(productId => ({
            providerId: goodsById.get(productId)?.providerId || providerId,
            productId,
            quantity: marketRules.quantityMin + Math.floor(random() * (marketRules.quantityMax - marketRules.quantityMin + 1)),
            priceOverride: null,
            pinned: false,
            generated: true
        }));
    }

    static #ids(entries) {
        return [...new Set((Array.isArray(entries) ? entries : [])
            .map(entry => String(entry?.goodId || ""))
            .filter(Boolean))];
    }

    static #createRandom(seed) {
        let hash = 2166136261;
        for (const character of seed) { hash ^= character.charCodeAt(0); hash = Math.imul(hash, 16777619); }
        return () => {
            hash += 0x6D2B79F5;
            let value = hash;
            value = Math.imul(value ^ (value >>> 15), value | 1);
            value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
            return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
        };
    }
}
