# Creating New Modules

## 🎮 Game Module Template

### Basic Structure

```javascript
import Module from '../core/Module.js';

class GameName extends Module {
    constructor(name, dependencies, config) {
        super(name, ['eventBus']); // Declare dependencies

        // Validate dependencies
        if (!dependencies.eventBus) {
            throw new Error('GameName requires EventBus dependency');
        }

        this._eventBus = dependencies.eventBus;
        this._config = config;

        Object.seal(this); // Prevent modification
    }

    async init() {
        this._validateNotDestroyed();

        // Set up event listeners
        this._eventBus.on('game:start', this._handleStart.bind(this), this.name);

        this._setInitialized();
    }

    async destroy() {
        this._validateNotDestroyed();

        // Cleanup: remove event listeners, DOM elements, timers
        this._eventBus.off('game:start', this._handleStart, this.name);

        this._setDestroyed();
    }

    // Private methods
    _handleStart(event) {
        this._validateInitialized();
        // Game logic here
    }
}

export default GameName;
```

### Registration in Application.js

```javascript
modules: [
    {
        name: 'gameName',
        path: './games/GameName.js',
        dependencies: ['eventBus'],
        config: {
            difficulty: 'medium',
            scoreToWin: 100
        }
    }
]
```

## 📋 DRS Exercise Module Template

### Using DRSExerciseInterface

```javascript
import DRSExerciseInterface from '../DRS/interfaces/DRSExerciseInterface.js';

class MyExercise extends DRSExerciseInterface {
    constructor() {
        super('MyExercise');

        // Internal state
        this.score = 0;
        this.attempts = 0;
        this.startTime = null;
        this.container = null;
    }

    // ⚠️ REQUIRED - Initialize exercise
    async init(config, content) {
        this.config = config;
        this.content = content;
        this.startTime = Date.now();

        // Validate content
        if (!content || !content.question) {
            throw new Error('MyExercise requires content with question');
        }
    }

    // ⚠️ REQUIRED - Render UI
    async render(container) {
        this.container = container;

        container.innerHTML = `
            <div class="exercise-container">
                <h2>${this.content.question}</h2>
                <input type="text" id="answer-input" />
                <button id="submit-btn">Submit</button>
            </div>
        `;

        // Event listeners
        container.querySelector('#submit-btn').addEventListener('click', () => {
            const answer = container.querySelector('#answer-input').value;
            this.handleUserInput('submit', { answer });
        });
    }

    // ⚠️ REQUIRED - Clean up
    async destroy() {
        if (this.container) {
            this.container.innerHTML = '';
        }
    }

    // ⚠️ REQUIRED - Validate answer
    async validate(userAnswer) {
        this.attempts++;

        const isCorrect = userAnswer.toLowerCase() === this.content.correctAnswer.toLowerCase();
        const score = isCorrect ? 100 - (this.attempts - 1) * 10 : 0;

        return {
            isCorrect,
            score: Math.max(score, 0),
            feedback: isCorrect ? 'Correct!' : 'Try again',
            explanation: `The correct answer is: ${this.content.correctAnswer}`
        };
    }

    // ⚠️ REQUIRED - Get results
    getResults() {
        return {
            score: this.score,
            attempts: this.attempts,
            timeSpent: Date.now() - this.startTime,
            completed: this.score > 0,
            details: {
                question: this.content.question,
                correctAnswer: this.content.correctAnswer
            }
        };
    }

    // ⚠️ REQUIRED - Handle user input
    handleUserInput(event, data) {
        if (event === 'submit') {
            this.validate(data.answer).then(result => {
                this.score = result.score;
                this.displayFeedback(result);
            });
        }
    }

    // ⚠️ REQUIRED - Mark as completed
    async markCompleted(results) {
        // Save to progress system
        await window.app.getCore().progressTracker.markExerciseCompleted(
            'my-exercise',
            this.content.id,
            results
        );
    }

    // ⚠️ REQUIRED - Get progress
    getProgress() {
        return {
            percentage: this.score > 0 ? 100 : 0,
            currentStep: 1,
            totalSteps: 1,
            itemsCompleted: this.score > 0 ? 1 : 0,
            itemsTotal: 1
        };
    }

    // ⚠️ REQUIRED - Get exercise type
    getExerciseType() {
        return 'my-exercise';
    }

    // ⚠️ REQUIRED - Get exercise config
    getExerciseConfig() {
        return {
            type: 'my-exercise',
            difficulty: this.config?.difficulty || 'medium',
            estimatedTime: 120, // seconds
            prerequisites: [],
            metadata: {
                hasAI: false,
                requiresInternet: false
            }
        };
    }

    // Helper methods
    displayFeedback(result) {
        const feedbackDiv = this.container.querySelector('.feedback') ||
                           document.createElement('div');
        feedbackDiv.className = 'feedback';
        feedbackDiv.textContent = result.feedback;

        if (!this.container.querySelector('.feedback')) {
            this.container.appendChild(feedbackDiv);
        }
    }
}

export default MyExercise;
```

## 📊 Progress Item Template

### Using ProgressItemInterface

```javascript
import ProgressItemInterface from '../DRS/interfaces/ProgressItemInterface.js';

class MyCustomItem extends ProgressItemInterface {
    constructor(id, metadata) {
        super('my-custom-item', id, metadata);
    }

    // ⚠️ REQUIRED - Validate item data
    validate() {
        if (!this.metadata.requiredField) {
            throw new Error('MyCustomItem requires requiredField in metadata');
        }
        return true;
    }

    // ⚠️ REQUIRED - Convert to JSON
    serialize() {
        return {
            ...this._getBaseSerialization(),
            customData: this.metadata.custom,
            timestamp: Date.now()
        };
    }

    // ⚠️ REQUIRED - Return item weight
    getWeight() {
        return ProgressItemInterface.WEIGHTS['my-custom-item'] || 5;
    }

    // ⚠️ REQUIRED - Check prerequisites
    canComplete(userProgress) {
        // Check if user has completed prerequisites
        const prerequisite = this.metadata.prerequisite;
        if (prerequisite) {
            return userProgress.hasCompleted(prerequisite);
        }
        return true;
    }
}

export default MyCustomItem;
```

## ✅ Checklist for New Modules

### For Game Modules
- [ ] Extends `Module` base class
- [ ] Validates dependencies in constructor
- [ ] Uses `Object.seal(this)` at end of constructor
- [ ] Implements `init()` and calls `_setInitialized()`
- [ ] Implements `destroy()` and calls `_setDestroyed()`
- [ ] Uses EventBus for all communication
- [ ] No direct access to other modules
- [ ] Registered in `Application.js` modules array

### For DRS Exercise Modules
- [ ] Extends `DRSExerciseInterface`
- [ ] Implements all 10 required methods
- [ ] Validates content in `init()`
- [ ] Cleans up in `destroy()`
- [ ] Returns correct format from `validate()`
- [ ] Integrates with progress system
- [ ] Tested with ImplementationValidator

### For Progress Items
- [ ] Extends `ProgressItemInterface`
- [ ] Implements all 4 required methods
- [ ] Validates data correctly
- [ ] Returns proper weight
- [ ] Checks prerequisites properly
- [ ] Added to ImplementationValidator

## 🚨 Common Mistakes to Avoid

1. **Forgetting Object.seal()** - Module can be modified externally
2. **Not validating dependencies** - Module fails at runtime
3. **Direct module access** - Use EventBus instead
4. **Missing required methods** - Red screen error at startup
5. **Not cleaning up** - Memory leaks on destroy
6. **Hardcoded paths** - Use dynamic content loading
7. **Skipping ImplementationValidator** - Interface violations not caught

## 📚 Examples in Codebase

- **Game Module**: `src/games/FlashcardLearning.js`
- **DRS Exercise**: `src/DRS/exercise-modules/VocabularyModule.js`
- **Progress Item**: `src/DRS/services/ProgressItemInterface.js`
- **Validation**: `src/DRS/services/ImplementationValidator.js`
