"use strict";
/**
 * Application Layer - Use Cases and Workflow Orchestration
 *
 * This layer implements the application's use cases using clean architecture principles.
 * It orchestrates domain services and coordinates between different layers.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.demonstrateApplicationLayer = exports.SomoniCompiler = exports.CompilationUseCase = exports.ValidationUseCase = exports.LexicalAnalysisUseCase = exports.MetricsCollectionService = exports.ErrorAggregationService = void 0;
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-unused-vars */
/* eslint-disable complexity */
const types_1 = require("../types");
const modular_lexer_compatible_1 = require("./modular-lexer-compatible");
// ===== DOMAIN SERVICES =====
class ErrorAggregationService {
    static aggregateErrors(lexicalErrors, syntaxErrors = [], typeErrors = []) {
        const errors = [];
        // Convert lexical errors
        lexicalErrors.forEach(error => {
            errors.push({
                message: error.message,
                line: error.line,
                column: error.column,
                severity: 'error',
                code: 'LEX001',
                category: 'lexical',
            });
        });
        // Add other error types here as more components are implemented
        return errors;
    }
}
exports.ErrorAggregationService = ErrorAggregationService;
class MetricsCollectionService {
    static createLexicalMetrics(tokens, errors, processingTime, sourceSize) {
        const tokenCounts = this.categorizeTokens(tokens);
        return {
            tokenCount: tokens.filter(t => t.type !== types_1.TokenType.EOF).length,
            identifierCount: tokenCounts.identifiers,
            keywordCount: tokenCounts.keywords,
            operatorCount: tokenCounts.operators,
            literalCount: tokenCounts.literals,
            processingTime,
            sourceSize,
        };
    }
    static categorizeTokens(tokens) {
        let identifiers = 0;
        let keywords = 0;
        let operators = 0;
        let literals = 0;
        tokens.forEach(token => {
            if (token.type === types_1.TokenType.IDENTIFIER) {
                identifiers++;
            }
            else if (this.isKeyword(token.type)) {
                keywords++;
            }
            else if (this.isOperator(token.type)) {
                operators++;
            }
            else if (this.isLiteral(token.type)) {
                literals++;
            }
        });
        return { identifiers, keywords, operators, literals };
    }
    static isKeyword(type) {
        const keywords = [
            types_1.TokenType.ТАҒЙИРЁБАНДА,
            types_1.TokenType.СОБИТ,
            types_1.TokenType.ФУНКСИЯ,
            types_1.TokenType.АГАР,
            types_1.TokenType.ВАГАРНА,
            types_1.TokenType.БАРОИ,
            types_1.TokenType.ТО,
            types_1.TokenType.БОЗГАШТ,
            types_1.TokenType.СИНФ,
            types_1.TokenType.ИНТЕРФЕЙС,
        ];
        return keywords.includes(type);
    }
    static isOperator(type) {
        const operators = [
            types_1.TokenType.PLUS,
            types_1.TokenType.MINUS,
            types_1.TokenType.MULTIPLY,
            types_1.TokenType.DIVIDE,
            types_1.TokenType.ASSIGN,
            types_1.TokenType.EQUAL,
            types_1.TokenType.LESS_THAN,
            types_1.TokenType.GREATER_THAN,
        ];
        return operators.includes(type);
    }
    static isLiteral(type) {
        return [types_1.TokenType.NUMBER, types_1.TokenType.STRING, types_1.TokenType.BOOLEAN].includes(type);
    }
}
exports.MetricsCollectionService = MetricsCollectionService;
// ===== USE CASE IMPLEMENTATIONS =====
class LexicalAnalysisUseCase {
    constructor(lexer = new modular_lexer_compatible_1.ModularLexer()) {
        this.lexer = lexer;
    }
    analyze(source, options = {}) {
        const startTime = performance.now();
        try {
            const result = this.lexer.tokenize(source);
            const endTime = performance.now();
            const processingTime = endTime - startTime;
            const metrics = MetricsCollectionService.createLexicalMetrics(result.tokens, result.errors, processingTime, source.length);
            return {
                tokens: result.tokens,
                errors: result.errors,
                metrics,
                success: result.errors.length === 0,
            };
        }
        catch (error) {
            const endTime = performance.now();
            const processingTime = endTime - startTime;
            return {
                tokens: [],
                errors: [new modular_lexer_compatible_1.LexicalError(`Unexpected error during lexical analysis: ${error}`, 0, 0, '')],
                metrics: {
                    tokenCount: 0,
                    identifierCount: 0,
                    keywordCount: 0,
                    operatorCount: 0,
                    literalCount: 0,
                    processingTime,
                    sourceSize: source.length,
                },
                success: false,
            };
        }
    }
}
exports.LexicalAnalysisUseCase = LexicalAnalysisUseCase;
class ValidationUseCase {
    validateSyntax(source) {
        // For now, this just checks if lexical analysis succeeds
        const lexicalUseCase = new LexicalAnalysisUseCase();
        const result = lexicalUseCase.analyze(source);
        const errors = result.errors.map(error => ({
            message: error.message,
            location: { line: error.line, column: error.column },
            category: 'syntax',
        }));
        return {
            isValid: errors.length === 0,
            errors,
            warnings: [],
        };
    }
    validateTypes(ast) {
        // Placeholder for type validation
        return {
            isValid: true,
            errors: [],
            warnings: [],
        };
    }
}
exports.ValidationUseCase = ValidationUseCase;
class CompilationUseCase {
    constructor(lexicalAnalysis = new LexicalAnalysisUseCase(), validation = new ValidationUseCase()) {
        this.lexicalAnalysis = lexicalAnalysis;
        this.validation = validation;
    }
    async compileSource(source, options = {}) {
        const startTime = performance.now();
        const errors = [];
        const warnings = [];
        try {
            // Step 1: Lexical Analysis
            console.log('🔤 Starting lexical analysis...');
            const lexicalStart = performance.now();
            const lexicalResult = this.lexicalAnalysis.analyze(source);
            const lexicalTime = performance.now() - lexicalStart;
            if (!lexicalResult.success) {
                errors.push(...ErrorAggregationService.aggregateErrors(lexicalResult.errors));
                return this.createFailureResult(errors, warnings, startTime, {
                    lexicalTime,
                    parseTime: 0,
                    typeCheckTime: 0,
                    codeGenTime: 0,
                    tokenCount: lexicalResult.tokens.length,
                    nodeCount: 0,
                    outputSize: 0,
                });
            }
            console.log(`✅ Lexical analysis completed: ${lexicalResult.tokens.length} tokens`);
            // Step 2: Syntax Validation
            console.log('🔍 Validating syntax...');
            const validationResult = this.validation.validateSyntax(source);
            if (!validationResult.isValid) {
                errors.push(...validationResult.errors.map(error => ({
                    message: error.message,
                    line: error.location.line,
                    column: error.location.column,
                    severity: 'error',
                    code: 'SYN001',
                    category: 'syntactic',
                })));
            }
            // Step 3: Basic Code Generation (placeholder)
            console.log('🔧 Generating JavaScript code...');
            const codeGenStart = performance.now();
            const output = this.generateJavaScript(lexicalResult.tokens, options);
            const codeGenTime = performance.now() - codeGenStart;
            const totalTime = performance.now() - startTime;
            const metrics = {
                lexicalTime,
                parseTime: 0, // Not implemented yet
                typeCheckTime: 0, // Not implemented yet
                codeGenTime,
                totalTime,
                tokenCount: lexicalResult.tokens.length,
                nodeCount: 0, // No AST yet
                outputSize: output.length,
            };
            console.log(`🎉 Compilation completed in ${totalTime.toFixed(2)}ms`);
            return {
                success: errors.length === 0,
                output,
                errors,
                warnings,
                metrics,
            };
        }
        catch (error) {
            const totalTime = performance.now() - startTime;
            errors.push({
                message: `Compilation failed: ${error}`,
                line: 0,
                column: 0,
                severity: 'error',
                code: 'COMP001',
                category: 'runtime',
            });
            return this.createFailureResult(errors, warnings, startTime, {
                lexicalTime: 0,
                parseTime: 0,
                typeCheckTime: 0,
                codeGenTime: 0,
                tokenCount: 0,
                nodeCount: 0,
                outputSize: 0,
            });
        }
    }
    createFailureResult(errors, warnings, startTime, partialMetrics) {
        const totalTime = performance.now() - startTime;
        return {
            success: false,
            errors,
            warnings,
            metrics: {
                lexicalTime: 0,
                parseTime: 0,
                typeCheckTime: 0,
                codeGenTime: 0,
                totalTime,
                tokenCount: 0,
                nodeCount: 0,
                outputSize: 0,
                ...partialMetrics,
            },
        };
    }
    generateJavaScript(tokens, options) {
        // Very basic token-to-JavaScript conversion for demonstration
        let output = '';
        let i = 0;
        while (i < tokens.length && tokens[i].type !== types_1.TokenType.EOF) {
            const token = tokens[i];
            switch (token.type) {
                case types_1.TokenType.ТАҒЙИРЁБАНДА:
                    output += 'let ';
                    break;
                case types_1.TokenType.СОБИТ:
                    output += 'const ';
                    break;
                case types_1.TokenType.ФУНКСИЯ:
                    output += 'function ';
                    break;
                case types_1.TokenType.АГАР:
                    output += 'if ';
                    break;
                case types_1.TokenType.ВАГАРНА:
                    output += 'else ';
                    break;
                case types_1.TokenType.БОЗГАШТ:
                    output += 'return ';
                    break;
                case types_1.TokenType.ДУРУСТ:
                    output += 'true';
                    break;
                case types_1.TokenType.НОДУРУСТ:
                    output += 'false';
                    break;
                case types_1.TokenType.ХОЛӢ:
                    output += 'null';
                    break;
                case types_1.TokenType.БЕҚИМАТ:
                    output += 'undefined';
                    break;
                default:
                    output += token.value;
                    break;
            }
            // Add space after most tokens except punctuation
            if (![
                types_1.TokenType.SEMICOLON,
                types_1.TokenType.COMMA,
                types_1.TokenType.DOT,
                types_1.TokenType.LEFT_PAREN,
                types_1.TokenType.LEFT_BRACE,
                types_1.TokenType.LEFT_BRACKET,
            ].includes(token.type) &&
                i < tokens.length - 1 &&
                ![
                    types_1.TokenType.RIGHT_PAREN,
                    types_1.TokenType.RIGHT_BRACE,
                    types_1.TokenType.RIGHT_BRACKET,
                    types_1.TokenType.SEMICOLON,
                    types_1.TokenType.COMMA,
                    types_1.TokenType.DOT,
                ].includes(tokens[i + 1].type)) {
                output += ' ';
            }
            i++;
        }
        return output;
    }
}
exports.CompilationUseCase = CompilationUseCase;
// ===== FACADE FOR EASY USAGE =====
class SomoniCompiler {
    constructor() {
        this.lexicalAnalysisUseCase = new LexicalAnalysisUseCase();
        this.validationUseCase = new ValidationUseCase();
        this.compilationUseCase = new CompilationUseCase(this.lexicalAnalysisUseCase, this.validationUseCase);
    }
    async compile(source, options) {
        return this.compilationUseCase.compileSource(source, options);
    }
    analyzeLexically(source, options) {
        return this.lexicalAnalysisUseCase.analyze(source, options);
    }
    validate(source) {
        return this.validationUseCase.validateSyntax(source);
    }
}
exports.SomoniCompiler = SomoniCompiler;
// ===== DEMO FUNCTION =====
async function demonstrateApplicationLayer() {
    console.log('🏗️  Application Layer Architecture Demo');
    console.log('==========================================\n');
    const code = `
тағйирёбанда исм = "Ҷаҳон";
функсия салом(номи) {
    бозгашт "Салом, " + номи + "!";
}

рақам натиҷа = 42;
мантиқӣ дуруст_аст = дуруст;
`;
    const compiler = new SomoniCompiler();
    console.log('📝 Source Code:');
    console.log(code);
    console.log();
    // Demonstrate lexical analysis
    console.log('🔤 Lexical Analysis:');
    const lexicalResult = compiler.analyzeLexically(code);
    console.log(`- Tokens: ${lexicalResult.metrics.tokenCount}`);
    console.log(`- Processing time: ${lexicalResult.metrics.processingTime.toFixed(2)}ms`);
    console.log(`- Success: ${lexicalResult.success}`);
    console.log();
    // Demonstrate validation
    console.log('🔍 Validation:');
    const validationResult = compiler.validate(code);
    console.log(`- Valid: ${validationResult.isValid}`);
    console.log(`- Errors: ${validationResult.errors.length}`);
    console.log();
    // Demonstrate full compilation
    console.log('🔧 Full Compilation:');
    const compilationResult = await compiler.compile(code, {
        target: 'javascript',
        optimize: false,
    });
    console.log(`- Success: ${compilationResult.success}`);
    console.log(`- Total time: ${compilationResult.metrics.totalTime.toFixed(2)}ms`);
    console.log(`- Output size: ${compilationResult.metrics.outputSize} characters`);
    if (compilationResult.success && compilationResult.output) {
        console.log('\n📤 Generated JavaScript:');
        console.log('```javascript');
        console.log(compilationResult.output);
        console.log('```');
    }
    if (compilationResult.errors.length > 0) {
        console.log('\n❌ Compilation Errors:');
        compilationResult.errors.forEach(error => {
            console.log(`- ${error.category}: ${error.message} at line ${error.line}`);
        });
    }
    console.log('\n✅ Application layer demonstration completed!');
}
exports.demonstrateApplicationLayer = demonstrateApplicationLayer;
// Run the demo if this file is executed directly
if (require.main === module) {
    demonstrateApplicationLayer().catch(console.error);
}
//# sourceMappingURL=application-layer.js.map