"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkflowVersioningService = void 0;
const workflow_validator_1 = require("./workflow-validator");
const enhanced_config_validator_1 = require("./enhanced-config-validator");
class WorkflowVersioningService {
    constructor(nodeRepository, apiClient) {
        this.nodeRepository = nodeRepository;
        this.apiClient = apiClient;
        this.DEFAULT_MAX_VERSIONS = 10;
    }
    async createBackup(workflowId, workflow, context) {
        const versions = this.nodeRepository.getWorkflowVersions(workflowId, 1);
        const nextVersion = versions.length > 0 ? versions[0].versionNumber + 1 : 1;
        const versionId = this.nodeRepository.createWorkflowVersion({
            workflowId,
            versionNumber: nextVersion,
            workflowName: workflow.name || 'Unnamed Workflow',
            workflowSnapshot: workflow,
            trigger: context.trigger,
            operations: context.operations,
            fixTypes: context.fixTypes,
            metadata: context.metadata
        });
        const pruned = this.nodeRepository.pruneWorkflowVersions(workflowId, this.DEFAULT_MAX_VERSIONS);
        return {
            versionId,
            versionNumber: nextVersion,
            pruned,
            message: pruned > 0
                ? `Backup created (version ${nextVersion}), pruned ${pruned} old version(s)`
                : `Backup created (version ${nextVersion})`
        };
    }
    async getVersionHistory(workflowId, limit = 10) {
        const versions = this.nodeRepository.getWorkflowVersions(workflowId, limit);
        return versions.map(v => ({
            id: v.id,
            workflowId: v.workflowId,
            versionNumber: v.versionNumber,
            workflowName: v.workflowName,
            trigger: v.trigger,
            operationCount: v.operations ? v.operations.length : undefined,
            fixTypesApplied: v.fixTypes || undefined,
            createdAt: v.createdAt,
            size: JSON.stringify(v.workflowSnapshot).length
        }));
    }
    async getVersion(versionId) {
        return this.nodeRepository.getWorkflowVersion(versionId);
    }
    async restoreVersion(workflowId, versionId, validateBefore = true) {
        if (!this.apiClient) {
            return {
                success: false,
                message: 'API client not configured - cannot restore workflow',
                workflowId,
                toVersionId: versionId || 0,
                backupCreated: false
            };
        }
        let versionToRestore = null;
        if (versionId) {
            versionToRestore = this.nodeRepository.getWorkflowVersion(versionId);
        }
        else {
            versionToRestore = this.nodeRepository.getLatestWorkflowVersion(workflowId);
        }
        if (!versionToRestore) {
            return {
                success: false,
                message: versionId
                    ? `Version ${versionId} not found`
                    : `No backup versions found for workflow ${workflowId}`,
                workflowId,
                toVersionId: versionId || 0,
                backupCreated: false
            };
        }
        if (validateBefore) {
            const validator = new workflow_validator_1.WorkflowValidator(this.nodeRepository, enhanced_config_validator_1.EnhancedConfigValidator);
            const validationResult = await validator.validateWorkflow(versionToRestore.workflowSnapshot, {
                validateNodes: true,
                validateConnections: true,
                validateExpressions: false,
                profile: 'runtime'
            });
            if (validationResult.errors.length > 0) {
                return {
                    success: false,
                    message: `Cannot restore - version ${versionToRestore.versionNumber} has validation errors`,
                    workflowId,
                    toVersionId: versionToRestore.id,
                    backupCreated: false,
                    validationErrors: validationResult.errors.map(e => e.message || 'Unknown error')
                };
            }
        }
        let backupResult;
        try {
            const currentWorkflow = await this.apiClient.getWorkflow(workflowId);
            backupResult = await this.createBackup(workflowId, currentWorkflow, {
                trigger: 'partial_update',
                metadata: {
                    reason: 'Backup before rollback',
                    restoringToVersion: versionToRestore.versionNumber
                }
            });
        }
        catch (error) {
            return {
                success: false,
                message: `Failed to create backup before restore: ${error.message}`,
                workflowId,
                toVersionId: versionToRestore.id,
                backupCreated: false
            };
        }
        try {
            await this.apiClient.updateWorkflow(workflowId, versionToRestore.workflowSnapshot);
            return {
                success: true,
                message: `Successfully restored workflow to version ${versionToRestore.versionNumber}`,
                workflowId,
                fromVersion: backupResult.versionNumber,
                toVersionId: versionToRestore.id,
                backupCreated: true,
                backupVersionId: backupResult.versionId
            };
        }
        catch (error) {
            return {
                success: false,
                message: `Failed to restore workflow: ${error.message}`,
                workflowId,
                toVersionId: versionToRestore.id,
                backupCreated: true,
                backupVersionId: backupResult.versionId
            };
        }
    }
    async deleteVersion(versionId) {
        const version = this.nodeRepository.getWorkflowVersion(versionId);
        if (!version) {
            return {
                success: false,
                message: `Version ${versionId} not found`
            };
        }
        this.nodeRepository.deleteWorkflowVersion(versionId);
        return {
            success: true,
            message: `Deleted version ${version.versionNumber} for workflow ${version.workflowId}`
        };
    }
    async deleteAllVersions(workflowId) {
        const count = this.nodeRepository.getWorkflowVersionCount(workflowId);
        if (count === 0) {
            return {
                deleted: 0,
                message: `No versions found for workflow ${workflowId}`
            };
        }
        const deleted = this.nodeRepository.deleteWorkflowVersionsByWorkflowId(workflowId);
        return {
            deleted,
            message: `Deleted ${deleted} version(s) for workflow ${workflowId}`
        };
    }
    async pruneVersions(workflowId, maxVersions = 10) {
        const pruned = this.nodeRepository.pruneWorkflowVersions(workflowId, maxVersions);
        const remaining = this.nodeRepository.getWorkflowVersionCount(workflowId);
        return { pruned, remaining };
    }
    async truncateAllVersions(confirm) {
        if (!confirm) {
            return {
                deleted: 0,
                message: 'Truncate operation not confirmed - no action taken'
            };
        }
        const deleted = this.nodeRepository.truncateWorkflowVersions();
        return {
            deleted,
            message: `Truncated workflow_versions table - deleted ${deleted} version(s)`
        };
    }
    async getStorageStats() {
        const stats = this.nodeRepository.getVersionStorageStats();
        return {
            totalVersions: stats.totalVersions,
            totalSize: stats.totalSize,
            totalSizeFormatted: this.formatBytes(stats.totalSize),
            byWorkflow: stats.byWorkflow.map((w) => ({
                workflowId: w.workflowId,
                workflowName: w.workflowName,
                versionCount: w.versionCount,
                totalSize: w.totalSize,
                totalSizeFormatted: this.formatBytes(w.totalSize),
                lastBackup: w.lastBackup
            }))
        };
    }
    async compareVersions(versionId1, versionId2) {
        const v1 = this.nodeRepository.getWorkflowVersion(versionId1);
        const v2 = this.nodeRepository.getWorkflowVersion(versionId2);
        if (!v1 || !v2) {
            throw new Error(`One or both versions not found: ${versionId1}, ${versionId2}`);
        }
        const nodes1 = new Set(v1.workflowSnapshot.nodes?.map((n) => n.id) || []);
        const nodes2 = new Set(v2.workflowSnapshot.nodes?.map((n) => n.id) || []);
        const addedNodes = [...nodes2].filter(id => !nodes1.has(id));
        const removedNodes = [...nodes1].filter(id => !nodes2.has(id));
        const commonNodes = [...nodes1].filter(id => nodes2.has(id));
        const modifiedNodes = [];
        for (const nodeId of commonNodes) {
            const node1 = v1.workflowSnapshot.nodes?.find((n) => n.id === nodeId);
            const node2 = v2.workflowSnapshot.nodes?.find((n) => n.id === nodeId);
            if (JSON.stringify(node1) !== JSON.stringify(node2)) {
                modifiedNodes.push(nodeId);
            }
        }
        const conn1Str = JSON.stringify(v1.workflowSnapshot.connections || {});
        const conn2Str = JSON.stringify(v2.workflowSnapshot.connections || {});
        const connectionChanges = conn1Str !== conn2Str ? 1 : 0;
        const settings1 = v1.workflowSnapshot.settings || {};
        const settings2 = v2.workflowSnapshot.settings || {};
        const settingChanges = this.diffObjects(settings1, settings2);
        return {
            versionId1,
            versionId2,
            version1Number: v1.versionNumber,
            version2Number: v2.versionNumber,
            addedNodes,
            removedNodes,
            modifiedNodes,
            connectionChanges,
            settingChanges
        };
    }
    formatBytes(bytes) {
        if (bytes === 0)
            return '0 Bytes';
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
    }
    diffObjects(obj1, obj2) {
        const changes = {};
        const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
        for (const key of allKeys) {
            if (JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {
                changes[key] = {
                    before: obj1[key],
                    after: obj2[key]
                };
            }
        }
        return changes;
    }
}
exports.WorkflowVersioningService = WorkflowVersioningService;
//# sourceMappingURL=workflow-versioning-service.js.map