import {
    generateNpc,
    getNpcGeneratorOptions,
    getNpcGeneratorProfileOptions,
    getNpcGenerators
} from "./npcs.js";
import {
    generateShip,
    getShipGeneratorOptions,
    getShipGeneratorProfileOptions,
    getShipGenerators
} from "./ships.js";
import {
    generateFaction,
    getFactionGeneratorOptions,
    getFactionGeneratorProfileOptions,
    getFactionGenerators
} from "./factions.js";
import {
    generateLocation,
    getLocationGeneratorOptions,
    getLocationGeneratorProfileOptions,
    getLocationGenerators
} from "./locations.js";

const API_VERSION = 1;
const GENERATORS = Object.freeze({
    npc: Object.freeze({ list: getNpcGenerators, options: getNpcGeneratorOptions, profile: getNpcGeneratorProfileOptions, generate: generateNpc }),
    ship: Object.freeze({ list: getShipGenerators, options: getShipGeneratorOptions, profile: getShipGeneratorProfileOptions, generate: generateShip }),
    faction: Object.freeze({ list: getFactionGenerators, options: getFactionGeneratorOptions, profile: getFactionGeneratorProfileOptions, generate: generateFaction }),
    location: Object.freeze({ list: getLocationGenerators, options: getLocationGeneratorOptions, profile: getLocationGeneratorProfileOptions, generate: generateLocation })
});

function definitionFor(entityType) {
    const normalized = String(entityType || "").trim().toLocaleLowerCase();
    const definition = GENERATORS[normalized];
    if (!definition) throw new Error(`Unsupported Nexus generator subject: ${normalized || "missing type"}.`);
    return { entityType: normalized, ...definition };
}

/**
 * Describes the live, registered creation vocabulary for one Nexus entity type.
 */
export async function inspectEntityGenerators(entityType, { generatorId = "", profileContext = {} } = {}) {
    const definition = definitionFor(entityType);
    const generators = definition.list();
    const selectedId = String(generatorId || "").trim();
    if (!selectedId) return { apiVersion: API_VERSION, entityType: definition.entityType, generators };
    const selected = generators.find(generator => generator.id === selectedId);
    if (!selected) throw new Error(`Unknown ${definition.entityType} generator: ${selectedId}.`);
    const [options, profileOptions] = await Promise.all([
        definition.options(selectedId),
        definition.profile(selectedId, foundry.utils.deepClone(profileContext || {}))
    ]);
    return {
        apiVersion: API_VERSION,
        entityType: definition.entityType,
        generators,
        selected,
        options: foundry.utils.deepClone(options || {}),
        profileOptions: foundry.utils.deepClone(profileOptions || {})
    };
}

/**
 * Produces an in-memory candidate through a registered generator. It never persists the candidate.
 */
export async function generateEntityCandidate(entityType, generatorId, options = {}) {
    if (!game.user?.isGM) throw new Error("Only a GM can generate Nexus entity candidates.");
    const definition = definitionFor(entityType);
    const selectedId = String(generatorId || "").trim();
    const generators = definition.list();
    if (!generators.some(generator => generator.id === selectedId)) {
        throw new Error(`Unknown ${definition.entityType} generator: ${selectedId || "missing ID"}.`);
    }
    const candidate = await definition.generate(selectedId, foundry.utils.deepClone(options || {}));
    if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
        throw new Error(`${selectedId} did not return a Nexus candidate.`);
    }
    return { apiVersion: API_VERSION, entityType: definition.entityType, generatorId: selectedId, candidate: foundry.utils.deepClone(candidate) };
}

export function getEntityGeneratorCapability() {
    return {
        apiVersion: API_VERSION,
        id: "augur-nexus.entity-generators",
        subjects: Object.keys(GENERATORS),
        operations: ["inspect", "generate-candidate"],
        persistence: "none"
    };
}
