/**
 * ToolConfigResolver
 *
 * Implements 3-tier hierarchy for tool configuration:
 * Item requirements > Roster allowances > Student accommodations
 *
 * Ensures IEP/504 compliance by properly handling accommodation requirements
 * while respecting item-level and test-level restrictions.
 *
 * Features:
 * - 3-tier configuration hierarchy
 * - IEP/504 accommodation support
 * - Item-specific tool requirements
 * - Test-level tool restrictions
 * - Type-safe configuration
 *
 * Part of PIE Assessment Toolkit.
 */
export class ToolConfigResolver {
    /**
     * Resolve configuration for a specific tool
     *
     * Hierarchy (highest to lowest priority):
     * 1. Item level: Item requires scientific calculator → must provide
     * 2. Roster level: Test blocks a tool → blocked regardless of accommodation
     * 3. Student level: IEP requires TTS → enabled unless blocked above
     *
     * @param toolId Tool identifier
     * @param itemConfig Item-level tool configuration
     * @param rosterConfig Roster-level tool allowances
     * @param studentProfile Student accommodation profile
     * @returns Resolved configuration or null if tool not available
     */
    resolveTool(toolId, itemConfig, rosterConfig, studentProfile) {
        // Check item level (highest priority)
        const itemTool = itemConfig?.[toolId];
        if (itemTool) {
            // Item explicitly configures this tool
            return {
                enabled: true,
                type: itemTool.type,
                required: itemTool.required ?? false,
                settings: itemTool.settings,
                source: "item",
            };
        }
        // Check roster level (blocks take precedence)
        const rosterAllowance = rosterConfig?.[toolId];
        if (rosterAllowance === "0") {
            // Roster explicitly blocks this tool
            return null;
        }
        if (rosterAllowance === "1") {
            // Roster allows this tool
            return {
                enabled: true,
                required: false,
                source: "roster",
            };
        }
        // Check student level (lowest priority)
        const hasAccommodation = studentProfile?.accommodations.includes(toolId) ?? false;
        if (hasAccommodation) {
            // Student has accommodation for this tool
            return {
                enabled: true,
                required: false,
                source: "student",
            };
        }
        // Tool not configured at any level
        return null;
    }
    /**
     * Resolve all tools from configuration
     *
     * @param input Configuration input
     * @returns Map of tool ID to resolved configuration
     */
    resolveAll(input) {
        const resolved = new Map();
        // Collect all tool IDs from all levels
        const allToolIds = new Set();
        // From item config
        if (input.itemConfig) {
            Object.keys(input.itemConfig).forEach((id) => allToolIds.add(id));
        }
        // From roster config
        if (input.rosterConfig) {
            Object.keys(input.rosterConfig).forEach((id) => allToolIds.add(id));
        }
        // From student accommodations
        if (input.studentProfile) {
            input.studentProfile.accommodations.forEach((id) => allToolIds.add(id));
        }
        // Resolve each tool
        for (const toolId of allToolIds) {
            const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
            if (config) {
                resolved.set(toolId, config);
            }
        }
        return resolved;
    }
    /**
     * Check if a tool is enabled
     *
     * @param toolId Tool identifier
     * @param input Configuration input
     * @returns true if tool is enabled
     */
    isToolEnabled(toolId, input) {
        const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
        return config?.enabled ?? false;
    }
    /**
     * Check if a tool is required
     *
     * @param toolId Tool identifier
     * @param input Configuration input
     * @returns true if tool is required
     */
    isToolRequired(toolId, input) {
        const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
        return config?.required ?? false;
    }
    /**
     * Get tool type (e.g., 'scientific' for calculator)
     *
     * @param toolId Tool identifier
     * @param input Configuration input
     * @returns Tool type or null
     */
    getToolType(toolId, input) {
        const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
        return config?.type ?? null;
    }
    /**
     * Get tool settings
     *
     * @param toolId Tool identifier
     * @param input Configuration input
     * @returns Tool settings or null
     */
    getToolSettings(toolId, input) {
        const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
        return config?.settings ?? null;
    }
    /**
     * Get list of all enabled tools
     *
     * @param input Configuration input
     * @returns Array of enabled tool IDs
     */
    getEnabledTools(input) {
        const resolved = this.resolveAll(input);
        return Array.from(resolved.entries())
            .filter(([_, config]) => config.enabled)
            .map(([toolId]) => toolId);
    }
    /**
     * Get list of required tools
     *
     * @param input Configuration input
     * @returns Array of required tool IDs
     */
    getRequiredTools(input) {
        const resolved = this.resolveAll(input);
        return Array.from(resolved.entries())
            .filter(([_, config]) => config.required)
            .map(([toolId]) => toolId);
    }
    /**
     * Validate that all required tools are available
     *
     * @param availableTools Set of available tool IDs
     * @param input Configuration input
     * @returns Object with validation result
     */
    validate(availableTools, input) {
        const requiredTools = this.getRequiredTools(input);
        const missingTools = requiredTools.filter((toolId) => !availableTools.has(toolId));
        return {
            valid: missingTools.length === 0,
            missingTools,
        };
    }
    /**
     * Merge multiple roster configurations (for complex assessments)
     *
     * More restrictive settings win (blocked > allowed).
     *
     * @param configs Array of roster configurations
     * @returns Merged configuration
     */
    mergeRosterConfigs(...configs) {
        const merged = {};
        for (const config of configs) {
            for (const [toolId, allowance] of Object.entries(config)) {
                // If any config blocks the tool, it's blocked
                if (allowance === "0") {
                    merged[toolId] = "0";
                }
                else if (!merged[toolId]) {
                    // If not already set, use this allowance
                    merged[toolId] = allowance;
                }
            }
        }
        return merged;
    }
    /**
     * Merge multiple student accommodation profiles
     *
     * Union of all accommodations.
     *
     * @param profiles Array of student profiles
     * @returns Merged profile
     */
    mergeStudentProfiles(...profiles) {
        const allAccommodations = new Set();
        for (const profile of profiles) {
            profile.accommodations.forEach((acc) => allAccommodations.add(acc));
        }
        return {
            accommodations: Array.from(allAccommodations),
        };
    }
}
//# sourceMappingURL=ToolConfigResolver.js.map