/**
 * Data Validator
 * Verify data structure cho từng game code
 *
 * Usage:
 * ```typescript
 * import { validateGameData, DataValidator } from 'game-iframe-sdk/client';
 *
 * const result = validateGameData('G001', receivedData);
 * if (!result.valid) {
 *     console.error('Invalid data:', result.errors);
 * }
 * ```
 */
import { GAME_CODES } from '../kit/GameDataHandler';
// =============================================================================
// SCHEMAS FOR EACH GAME CODE
// =============================================================================
const QUIZ_BASE_SCHEMA = {
    id: { type: 'string', required: true, description: 'Unique question ID' },
    options: { type: 'array', required: true, arrayItemType: 'string', description: 'Answer options' },
    answer: { type: 'number', required: true, description: 'Correct answer index (0-based)' },
};
const SCHEMAS = {
    // Quiz variants
    G001: {
        ...QUIZ_BASE_SCHEMA,
        question: { type: 'string', required: true, description: 'Text question' },
    },
    G002: {
        ...QUIZ_BASE_SCHEMA,
        question_audio: { type: 'string', required: true, description: 'Audio URL for question' },
    },
    G003: {
        ...QUIZ_BASE_SCHEMA,
        question: { type: 'string', required: true, description: 'Text question' },
        // options are audio URLs
    },
    G004: {
        ...QUIZ_BASE_SCHEMA,
        question_image: { type: 'string', required: true, description: 'Image URL for question' },
        question: { type: 'string', required: false, description: 'Optional text hint' },
    },
    // G005: Quiz Text-Image (options are image URLs, client picks index)
    G005: {
        ...QUIZ_BASE_SCHEMA,
        question: { type: 'string', required: true, description: 'Text question' },
        // options are image URLs, answer is index pointing to correct image
    },
    // Sequence Word variants
    G110: {
        id: { type: 'string', required: true },
        word: { type: 'string', required: true, description: 'The word to arrange' },
        parts: { type: 'array', required: true, arrayItemType: 'string', description: 'Letters/parts to arrange' },
        answer: { type: 'array', required: true, arrayItemType: 'string', description: 'Correct order' },
    },
    G111: {
        id: { type: 'string', required: true },
        word: { type: 'string', required: true },
        parts: { type: 'array', required: true, arrayItemType: 'string' },
        answer: { type: 'array', required: true, arrayItemType: 'string' },
        audio_url: { type: 'string', required: true, description: 'Audio hint URL' },
    },
    G112: {
        id: { type: 'string', required: true },
        word: { type: 'string', required: true },
        parts: { type: 'array', required: true, arrayItemType: 'string' },
        answer: { type: 'array', required: true, arrayItemType: 'string' },
        audio_url: { type: 'string', required: true },
    },
    G113: {
        id: { type: 'string', required: true },
        word: { type: 'string', required: true },
        parts: { type: 'array', required: true, arrayItemType: 'string' },
        answer: { type: 'array', required: true, arrayItemType: 'string' },
        audio_url: { type: 'string', required: true },
    },
    // Sequence Sentence variants
    G120: {
        id: { type: 'string', required: true },
        sentence: { type: 'string', required: false, description: 'Full sentence (hint)' },
        parts: { type: 'array', required: true, arrayItemType: 'string', description: 'Words to arrange' },
        answer: { type: 'array', required: true, arrayItemType: 'string', description: 'Correct word order' },
    },
    G121: {
        id: { type: 'string', required: true },
        sentence: { type: 'string', required: false },
        parts: { type: 'array', required: true, arrayItemType: 'string' },
        answer: { type: 'array', required: true, arrayItemType: 'string' },
        audio_url: { type: 'string', required: true },
    },
    G122: {
        id: { type: 'string', required: true },
        sentence: { type: 'string', required: false },
        parts: { type: 'array', required: true, arrayItemType: 'string' },
        answer: { type: 'array', required: true, arrayItemType: 'string' },
        audio_url: { type: 'string', required: true },
    },
    G123: {
        id: { type: 'string', required: true },
        sentence: { type: 'string', required: false },
        parts: { type: 'array', required: true, arrayItemType: 'string' },
        answer: { type: 'array', required: true, arrayItemType: 'string' },
        audio_url: { type: 'string', required: true },
    }
};
// =============================================================================
// VALIDATOR
// =============================================================================
/**
 * Validate a single item against schema
 */
function validateItem(item, schema, itemIndex) {
    const errors = [];
    if (!item || typeof item !== 'object') {
        errors.push(`Item [${itemIndex}]: Must be an object`);
        return errors;
    }
    for (const [field, fieldSchema] of Object.entries(schema)) {
        const value = item[field];
        // Check required
        if (fieldSchema.required && (value === undefined || value === null)) {
            errors.push(`Item [${itemIndex}].${field}: Required field is missing`);
            continue;
        }
        // Skip validation if optional and not present
        if (!fieldSchema.required && (value === undefined || value === null)) {
            continue;
        }
        // Check type
        const actualType = Array.isArray(value) ? 'array' : typeof value;
        if (fieldSchema.type !== 'any' && actualType !== fieldSchema.type) {
            errors.push(`Item [${itemIndex}].${field}: Expected ${fieldSchema.type}, got ${actualType}`);
            continue;
        }
        // Check array items
        if (fieldSchema.type === 'array' && fieldSchema.arrayItemType && fieldSchema.arrayItemType !== 'any') {
            for (let i = 0; i < value.length; i++) {
                const itemType = typeof value[i];
                if (itemType !== fieldSchema.arrayItemType) {
                    errors.push(`Item [${itemIndex}].${field}[${i}]: Expected ${fieldSchema.arrayItemType}, got ${itemType}`);
                }
            }
        }
    }
    return errors;
}
/**
 * Validate game data payload
 */
export function validateGameData(gameCode, payload) {
    const errors = [];
    const warnings = [];
    // Check game code
    if (!GAME_CODES[gameCode]) {
        errors.push(`Unknown game code: ${gameCode}`);
        return { valid: false, errors, warnings };
    }
    // Check payload structure
    if (!payload || typeof payload !== 'object') {
        errors.push('Payload must be an object');
        return { valid: false, errors, warnings };
    }
    // Check data array
    const items = payload.data || payload.items || payload.questions;
    if (!items) {
        errors.push('Missing data array (expected "data", "items", or "questions")');
        return { valid: false, errors, warnings };
    }
    if (!Array.isArray(items)) {
        errors.push('"data" must be an array');
        return { valid: false, errors, warnings };
    }
    if (items.length === 0) {
        warnings.push('Data array is empty');
    }
    // Validate each item
    const schema = SCHEMAS[gameCode];
    for (let i = 0; i < items.length; i++) {
        const itemErrors = validateItem(items[i], schema, i);
        errors.push(...itemErrors);
    }
    // Check for duplicate IDs
    const ids = items.map((item) => item.id).filter(Boolean);
    const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
    if (duplicates.length > 0) {
        warnings.push(`Duplicate IDs found: ${[...new Set(duplicates)].join(', ')}`);
    }
    return {
        valid: errors.length === 0,
        errors,
        warnings,
    };
}
/**
 * Get schema for a game code
 */
export function getSchema(gameCode) {
    return SCHEMAS[gameCode] ?? null;
}
/**
 * Get schema documentation for a game code
 */
export function getSchemaDoc(gameCode) {
    const schema = SCHEMAS[gameCode];
    if (!schema)
        return `Unknown game code: ${gameCode}`;
    const gameInfo = GAME_CODES[gameCode];
    const lines = [
        `## ${gameCode}: ${gameInfo.name}`,
        `Category: ${gameInfo.category}`,
        '',
        '### Fields:',
    ];
    for (const [field, fieldSchema] of Object.entries(schema)) {
        const required = fieldSchema.required ? '(required)' : '(optional)';
        let type = fieldSchema.type;
        if (fieldSchema.arrayItemType) {
            type = `${fieldSchema.type}<${fieldSchema.arrayItemType}>`;
        }
        lines.push(`- **${field}**: ${type} ${required}`);
        if (fieldSchema.description) {
            lines.push(`  - ${fieldSchema.description}`);
        }
    }
    return lines.join('\n');
}
// =============================================================================
// DATA VALIDATOR CLASS
// =============================================================================
export class DataValidator {
    constructor(gameCode) {
        this.gameCode = gameCode;
    }
    validate(payload) {
        return validateGameData(this.gameCode, payload);
    }
    getSchema() {
        return getSchema(this.gameCode);
    }
    getSchemaDoc() {
        return getSchemaDoc(this.gameCode);
    }
}
//# sourceMappingURL=DataValidator.js.map