"use strict";

var __awaiter = this && this.__awaiter || function(thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))((function(resolve, reject) {
        function fulfilled(value) {
            try {
                step(generator.next(value));
            } catch (e) {
                reject(e);
            }
        }
        function rejected(value) {
            try {
                step(generator.throw(value));
            } catch (e) {
                reject(e);
            }
        }
        function step(result) {
            var value;
            result.done ? resolve(result.value) : (value = result.value, value instanceof P ? value : new P((function(resolve) {
                resolve(value);
            }))).then(fulfilled, rejected);
        }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    }));
};

Object.defineProperty(exports, "__esModule", {
    value: !0
}), exports.CrossSheetFormulaHandler = void 0;

const cross_sheet_formula_manager_1 = require("./cross-sheet-formula-manager"), cross_sheet_data_synchronizer_1 = require("./cross-sheet-data-synchronizer"), cross_sheet_formula_validator_1 = require("./cross-sheet-formula-validator");

class CrossSheetFormulaHandler {
    constructor(formulaEngine, sheetManager, formulaManager) {
        this.options = {
            enableCaching: !0,
            enableValidation: !0,
            syncTimeout: 50,
            maxRecursionDepth: 100
        }, this.isCalculating = !1, this.calculationQueue = [], this.calculationResults = new Map, 
        this.formulaEngine = formulaEngine, this.formulaManager = formulaManager, this.crossSheetManager = new cross_sheet_formula_manager_1.CrossSheetFormulaManager(formulaEngine, sheetManager), 
        this.dataSynchronizer = new cross_sheet_data_synchronizer_1.CrossSheetDataSynchronizer(formulaEngine, this.crossSheetManager), 
        this.validator = new cross_sheet_formula_validator_1.CrossSheetFormulaValidator(formulaEngine, this.crossSheetManager, sheetManager);
    }
    setCrossSheetFormula(cell, formula) {
        return __awaiter(this, void 0, void 0, (function*() {
            const startTime = performance.now();
            try {
                if (this.options.enableValidation) {
                    const validation = this.validator.validateFormulaSyntax(formula);
                    if (!validation.valid) return {
                        value: null,
                        error: validation.error,
                        dependencies: [],
                        calculationTime: performance.now() - startTime
                    };
                }
                let result;
                this.crossSheetManager.registerCrossSheetReference(formula, cell), this.formulaEngine.setCellContent(cell, formula), 
                result = this.formulaManager ? this.formulaManager.getCellValue(cell) : this.formulaEngine.getCellValue(cell);
                const dependencies = this.formulaEngine.getCellPrecedents(cell), calculationResult = {
                    value: result.value,
                    error: result.error,
                    dependencies: dependencies,
                    calculationTime: performance.now() - startTime
                };
                return this.options.enableCaching && this.cacheCalculationResult(cell, calculationResult), 
                calculationResult;
            } catch (error) {
                return {
                    value: null,
                    error: error instanceof Error ? error.message : "Unknown error",
                    dependencies: [],
                    calculationTime: performance.now() - startTime
                };
            }
        }));
    }
    getCrossSheetValue(cell) {
        return __awaiter(this, void 0, void 0, (function*() {
            const startTime = performance.now();
            try {
                if (this.options.enableCaching) {
                    const cached = this.getCachedResult(cell);
                    if (cached) return Object.assign(Object.assign({}, cached), {
                        calculationTime: performance.now() - startTime
                    });
                }
                if (!this.formulaEngine.getCellFormula(cell)) return {
                    value: null,
                    error: "No formula found",
                    dependencies: [],
                    calculationTime: performance.now() - startTime
                };
                let result;
                result = this.formulaManager ? this.formulaManager.getCellValue(cell) : this.formulaEngine.getCellValue(cell);
                const dependencies = this.formulaEngine.getCellPrecedents(cell), calculationResult = {
                    value: result.value,
                    error: result.error,
                    dependencies: dependencies,
                    calculationTime: performance.now() - startTime
                };
                return this.options.enableCaching && this.cacheCalculationResult(cell, calculationResult), 
                calculationResult;
            } catch (error) {
                return {
                    value: null,
                    error: error instanceof Error ? error.message : "Unknown error",
                    dependencies: [],
                    calculationTime: performance.now() - startTime
                };
            }
        }));
    }
    updateCrossSheetReferences(targetSheet, changedCells) {
        return __awaiter(this, void 0, void 0, (function*() {
            yield this.crossSheetManager.updateCrossSheetReferences(targetSheet, changedCells);
        }));
    }
    validateCrossSheetFormula(cell) {
        const formula = this.formulaEngine.getCellFormula(cell);
        if (!formula) return {
            valid: !1,
            errors: [ {
                type: "MISSING_REFERENCE",
                message: "No formula found",
                sheet: cell.sheet,
                cell: cell
            } ],
            warnings: []
        };
        const syntaxValidation = this.validator.validateFormulaSyntax(formula);
        return {
            valid: syntaxValidation.valid,
            errors: syntaxValidation.error ? [ {
                type: "MISSING_REFERENCE",
                message: syntaxValidation.error,
                sheet: cell.sheet,
                cell: cell
            } ] : [],
            warnings: []
        };
    }
    validateAllCrossSheetFormulas() {
        return this.validator.validateAllSheets();
    }
    getCrossSheetDependencies() {
        return this.dataSynchronizer.getCrossSheetDependencies();
    }
    recalculateAllCrossSheetFormulas() {
        return __awaiter(this, void 0, void 0, (function*() {
            const allSheets = this.formulaEngine.getAllSheets();
            for (const sheetInfo of allSheets) {
                const formulas = this.formulaEngine.exportFormulas(sheetInfo.key);
                for (const [cellRef, formula] of Object.entries(formulas)) if (this.hasCrossSheetReference(formula)) {
                    const cell = this.parseA1Notation(cellRef), cellWithSheet = {
                        sheet: sheetInfo.key,
                        row: cell.row,
                        col: cell.col
                    };
                    yield this.recalculateFormula(cellWithSheet);
                }
            }
        }));
    }
    recalculateFormula(cell) {
        return __awaiter(this, void 0, void 0, (function*() {
            return yield this.getCrossSheetValue(cell);
        }));
    }
    hasCrossSheetReference(formula) {
        return formula.includes("!");
    }
    cacheCalculationResult(cell, result) {
        const cacheKey = this.getCacheKey(cell);
        this.calculationResults.set(cacheKey, result);
    }
    getCachedResult(cell) {
        const cacheKey = this.getCacheKey(cell);
        return this.calculationResults.get(cacheKey) || null;
    }
    getCacheKey(cell) {
        return `${cell.sheet}!${this.getA1Notation(cell.row, cell.col)}`;
    }
    parseA1Notation(a1Notation) {
        const match = a1Notation.match(/^([A-Z]+)([0-9]+)$/);
        if (!match) throw new Error(`Invalid cell reference: ${a1Notation}`);
        const colLetters = match[1], rowNumber = parseInt(match[2], 10);
        let col = 0;
        for (let i = 0; i < colLetters.length; i++) col = 26 * col + (colLetters.charCodeAt(i) - 65);
        return {
            row: rowNumber - 1,
            col: col
        };
    }
    getA1Notation(row, col) {
        let colStr = "", tempCol = col;
        do {
            colStr = String.fromCharCode(65 + tempCol % 26) + colStr, tempCol = Math.floor(tempCol / 26) - 1;
        } while (tempCol >= 0);
        return `${colStr}${row + 1}`;
    }
    updateOptions(options) {
        this.options = Object.assign(Object.assign({}, this.options), options), this.dataSynchronizer.updateSyncOptions({
            immediate: this.options.enableCaching,
            timeout: this.options.syncTimeout
        });
    }
    getHandlerStatus() {
        return {
            isCalculating: this.isCalculating,
            pendingCalculations: this.calculationQueue.length,
            cacheSize: this.calculationResults.size,
            options: Object.assign({}, this.options)
        };
    }
    clearCache() {
        this.calculationResults.clear(), this.crossSheetManager.clearCache(), this.validator.clearCache();
    }
    addDataChangeListener(sheet, listener) {
        this.dataSynchronizer.addDataChangeListener(sheet, listener);
    }
    removeDataChangeListener(sheet, listener) {
        this.dataSynchronizer.removeDataChangeListener(sheet, listener);
    }
    forceSync() {
        return __awaiter(this, void 0, void 0, (function*() {
            yield this.dataSynchronizer.forceSync();
        }));
    }
    destroy() {
        this.clearCache(), this.calculationResults.clear(), this.calculationQueue = [], 
        this.crossSheetManager.destroy(), this.dataSynchronizer.destroy(), this.validator.destroy();
    }
}

exports.CrossSheetFormulaHandler = CrossSheetFormulaHandler;
//# sourceMappingURL=cross-sheet-formula-handler.js.map