/*
 * @Author: Copilot
 * @Date: 2026-01-28
 * @Description: Rollback approval comments field transformations
 * 
 * This endpoint reverts fields that were transformed by the transform endpoint
 * back to their original input type format.
 */

const { MongoClient } = require('mongodb');

// MongoDB connection
let client = null;
let db = null;

async function connectToMongoDB() {
    if (db) {
        return db;
    }

    const mongoUrl = process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/steedos';
    try {
        client = new MongoClient(mongoUrl);
        await client.connect();
        
        const dbName = mongoUrl.split('/').pop().split('?')[0];
        db = client.db(dbName);
        return db;
    } catch (error) {
        console.error('Failed to connect to MongoDB:', error.message);
        throw error;
    }
}

async function getCollection(name) {
    const database = await connectToMongoDB();
    return database.collection(name);
}

/**
 * Process fields array and return bulk operations for rollback
 * Implements field-level error handling for silent failure
 */
function processFieldsArrayForRollback(fields, pathPrefix, formId, formName) {
    const updates = [];
    const unsets = [];
    let fieldCount = 0;  // Track actual fields processed
    const fieldErrors = [];  // Track field-specific errors
    
    if (!Array.isArray(fields)) {
        return { updates, unsets, fieldCount, fieldErrors };
    }
    
    for (let i = 0; i < fields.length; i++) {
        const field = fields[i];
        
        // Only rollback fields that were transformed (Idempotency principle)
        if (field.__approval_comments_transformed === true) {
            try {
                fieldCount++;  // Count this field
                
                // Zero Loss principle: Restore type with priority to stored original type
                const originalType = field.__approval_comments_original_type || 'input';
                updates.push({
                    index: i,
                    path: `${pathPrefix}.${i}.type`,
                    value: originalType
                });
                
                // Restore original formula if exists
                if (field.__approval_comments_original_formula) {
                    updates.push({
                        index: i,
                        path: `${pathPrefix}.${i}.formula`,
                        value: field.__approval_comments_original_formula
                    });
                }
                
                // Restore original default_value if exists
                if (field.__approval_comments_original_default_value) {
                    updates.push({
                        index: i,
                        path: `${pathPrefix}.${i}.default_value`,
                        value: field.__approval_comments_original_default_value
                    });
                }
                
                // Rename __approval_comments_original__amisField back to _amisField if it exists
                if (field.__approval_comments_original__amisField) {
                    updates.push({
                        index: i,
                        path: `${pathPrefix}.${i}._amisField`,
                        value: field.__approval_comments_original__amisField
                    });
                }
                
                // Remove added properties
                unsets.push(`${pathPrefix}.${i}.__approval_comments_transformed`);
                unsets.push(`${pathPrefix}.${i}.config`);
                unsets.push(`${pathPrefix}.${i}.__approval_comments_original__amisField`);
                unsets.push(`${pathPrefix}.${i}.__approval_comments_original_type`);  // Remove backup
                unsets.push(`${pathPrefix}.${i}.__approval_comments_original_formula`);  // Remove backup
                unsets.push(`${pathPrefix}.${i}.__approval_comments_original_default_value`);  // Remove backup
            } catch (error) {
                // Silent Failure principle: Record error but continue processing
                fieldErrors.push({
                    formId: formId,
                    formName: formName,
                    fieldPath: `${pathPrefix}.${i}`,
                    fieldCode: field.code || field.name || 'unknown',
                    error: error.message
                });
            }
        }
    }
    
    return { updates, unsets, fieldCount, fieldErrors };
}

module.exports = {
    rest: {
        method: 'GET',
        fullPath: '/api/workflow/rollbackApprovalCommentsField'
    },
    params: {
        batchSize: { type: 'number', optional: true, convert: true },
        dryRun: { type: 'boolean', optional: true, convert: true },
        fid: { type: 'string', optional: true }  // Flow ID to rollback single flow
    },
    async handler(ctx) {
        const { user } = ctx.meta;

        // Check if user exists and is space admin
        if (!user || user.is_space_admin !== true) {
            throw new Error('只有管理员才能执行此操作');
        }

        const { batchSize = 500, dryRun = false, fid } = ctx.params;
        
        const formsCollection = await getCollection('forms');
        
        // Build query filter
        const query = {
            state: 'enabled',  // Only process enabled forms
            $or: [
                { 'current.fields.__approval_comments_transformed': true },
                { 'historys.fields.__approval_comments_transformed': true }
            ]
        };
        
        // If fid is provided, query flows collection to get form ID
        if (fid) {
            const flowsCollection = await getCollection('flows');
            const flow = await flowsCollection.findOne({ _id: fid });
            
            if (!flow) {
                throw new Error(`Flow with ID ${fid} not found`);
            }
            
            if (!flow.form) {
                throw new Error(`Flow ${fid} does not have a form associated`);
            }
            
            // Add form ID filter
            query._id = flow.form;
        }

        // Use cursor to find forms with transformed fields
        const cursor = formsCollection.find(query);
        
        const results = {
            totalForms: 0,
            totalFields: 0,
            errors: []
        };
        
        const bulkOperations = [];

        // Process forms one by one using cursor
        while (await cursor.hasNext()) {
            const form = await cursor.next();
            try {
                let formUpdated = false;
                const formUpdate = {};
                const formUnset = {};
                let formFieldCount = 0;  // Track actual fields rolled back
                
                // Process current.fields
                if (form.current && Array.isArray(form.current.fields)) {
                    const { updates, unsets, fieldCount, fieldErrors } = processFieldsArrayForRollback(
                        form.current.fields, 
                        'current.fields',
                        form._id,
                        form.name
                    );
                    
                    // Add field-level errors to results
                    if (fieldErrors && fieldErrors.length > 0) {
                        results.errors.push(...fieldErrors);
                    }
                    
                    if (updates.length > 0 || unsets.length > 0) {
                        formUpdated = true;
                        formFieldCount += fieldCount;  // Add field count, not operation count
                        
                        // Build $set updates
                        for (const update of updates) {
                            formUpdate[update.path] = update.value;
                        }
                        
                        // Build $unset
                        for (const path of unsets) {
                            formUnset[path] = '';
                        }
                    }
                }
                
                // Process historys[].fields (Full Coverage principle)
                if (Array.isArray(form.historys)) {
                    for (let h = 0; h < form.historys.length; h++) {
                        const history = form.historys[h];
                        if (Array.isArray(history.fields)) {
                            const { updates, unsets, fieldCount, fieldErrors } = processFieldsArrayForRollback(
                                history.fields,
                                `historys.${h}.fields`,
                                form._id,
                                form.name
                            );
                            
                            // Add field-level errors to results
                            if (fieldErrors && fieldErrors.length > 0) {
                                results.errors.push(...fieldErrors);
                            }
                            
                            if (updates.length > 0 || unsets.length > 0) {
                                formUpdated = true;
                                formFieldCount += fieldCount;  // Add field count, not operation count
                                
                                // Build $set updates
                                for (const update of updates) {
                                    formUpdate[update.path] = update.value;
                                }
                                
                                // Build $unset
                                for (const path of unsets) {
                                    formUnset[path] = '';
                                }
                            }
                        }
                    }
                }
                
                // Restore root amis_schema from backup if exists
                if (form.__approval_comments_original__amis_schema) {
                    formUpdated = true;
                    
                    // Restore original amis_schema
                    formUpdate.amis_schema = form.__approval_comments_original__amis_schema;
                    
                    // Remove backup
                    formUnset.__approval_comments_original__amis_schema = '';
                }
                
                if (formUpdated) {
                    results.totalForms++;
                    results.totalFields += formFieldCount;  // Add actual field count
                    
                    if (!dryRun) {
                        const updateDoc = {};
                        if (Object.keys(formUpdate).length > 0) {
                            updateDoc.$set = formUpdate;
                        }
                        if (Object.keys(formUnset).length > 0) {
                            updateDoc.$unset = formUnset;
                        }
                        
                        bulkOperations.push({
                            updateOne: {
                                filter: { _id: form._id },
                                update: updateDoc
                            }
                        });
                        
                        // Execute bulk write in batches
                        if (bulkOperations.length >= batchSize) {
                            await formsCollection.bulkWrite(bulkOperations, { ordered: false });
                            bulkOperations.length = 0; // Clear array
                        }
                    }
                }
            } catch (error) {
                console.error(`Error processing form ${form._id}:`, error);
                results.errors.push({
                    formId: form._id,
                    formName: form.name,
                    error: error.message
                });
            }
        }
        
        // Execute remaining bulk operations
        if (!dryRun && bulkOperations.length > 0) {
            try {
                await formsCollection.bulkWrite(bulkOperations, { ordered: false });
            } catch (error) {
                console.error('Error executing final bulk write:', error);
                results.errors.push({
                    error: 'Final bulk write failed: ' + error.message
                });
            }
        }
        
        return {
            ...results,
            dryRun,
            message: dryRun ? 'Dry run completed - no changes made' : 'Rollback completed'
        };
    }
};
