/**
 * Customer Database Module - JavaScript Wrapper for Python Implementation
 * 
 * This module provides the same API as the original customerDb.js,
 * but calls Python functions via command line interface.
 */

const { execFile } = require('child_process');
const { promisify } = require('util');
const path = require('path');

const execFileAsync = promisify(execFile);

// Determine Python path - prefer virtual environment python if available
const PYTHON_PATH = process.env.PYTHON_PATH || 
                   (process.platform === 'win32' ? 'python' : 'python3');

// Path to Python module
const PYTHON_MODULE_PATH = path.join(__dirname, '..', 'src', 'services', 'customer_db.py');

/**
 * Call Python function with arguments
 * @param {string} functionName - Name of the Python function to call
 * @param {Object} args - Arguments for the function
 * @returns {Promise<any>} - Result from Python function
 */
async function callPythonFunction(functionName, args = {}) {
    try {
        // Build command line arguments
        const cliArgs = ['--function', functionName];
        
        // Add function-specific arguments
        if (functionName === 'getCustomerByPhone' && args.phone) {
            cliArgs.push('--phone', args.phone);
        } else if (functionName === 'searchCustomer' && args.query) {
            cliArgs.push('--query', args.query);
            if (args.limit) {
                cliArgs.push('--limit', args.limit.toString());
            }
        } else if (functionName === 'getSearchCount' && args.query) {
            cliArgs.push('--query', args.query);
        } else if (functionName === 'executeReadOnlyQuery' && args.sql) {
            cliArgs.push('--sql', args.sql);
        }
        
        // Add timeout
        cliArgs.push('--timeout', '30');
        
        // Execute Python script
        const { stdout, stderr } = await execFileAsync(PYTHON_PATH, [PYTHON_MODULE_PATH, ...cliArgs], {
            cwd: path.join(__dirname, '..'),
            env: { ...process.env, PYTHONUNBUFFERED: '1' },
            timeout: 35000, // 35 seconds timeout
            maxBuffer: 10 * 1024 * 1024, // 10MB buffer for large results
        });
        
        if (stderr && stderr.trim()) {
            console.warn(`Python stderr: ${stderr}`);
        }
        
        // Parse JSON output
        const result = JSON.parse(stdout.trim());
        
        // Handle Python errors
        if (result && result.error) {
            console.error(`Python function ${functionName} error:`, result.error);
            throw new Error(result.error);
        }
        
        return result;
        
    } catch (error) {
        console.error(`Error calling Python function ${functionName}:`, error);
        
        // Provide more helpful error messages
        if (error.code === 'ENOENT') {
            throw new Error(`Python not found at ${PYTHON_PATH}. Make sure Python 3.8+ is installed and in PATH.`);
        } else if (error.code === 'ETIMEDOUT' || error.signal === 'SIGTERM') {
            throw new Error(`Python function ${functionName} timed out after 35 seconds.`);
        } else if (error instanceof SyntaxError) {
            throw new Error(`Invalid JSON response from Python: ${error.message}`);
        }
        
        throw error;
    }
}

/**
 * Test database connection
 * @returns {Promise<boolean>} - True if connection successful
 */
async function testConnection() {
    try {
        const result = await callPythonFunction('testConnection');
        return result === true;
    } catch (error) {
        console.error('Database connection test failed:', error.message);
        return false;
    }
}

/**
 * Get customer by phone number with format normalization
 * @param {string} phoneNumber - Phone number to search for
 * @returns {Promise<Object|null>} - Customer object or null if not found
 */
async function getCustomerByPhone(phoneNumber) {
    try {
        const result = await callPythonFunction('getCustomerByPhone', { phone: phoneNumber });
        return result || null;
    } catch (error) {
        console.error('getCustomerByPhone error:', error.message);
        return null;
    }
}

/**
 * Search customers by name, phone, status, or profile
 * @param {string} query - Search term
 * @param {number} limit - Maximum results (default: 5)
 * @returns {Promise<Array>} - Array of customer objects
 */
async function searchCustomer(query, limit = 5) {
    try {
        const result = await callPythonFunction('searchCustomer', { query, limit });
        return Array.isArray(result) ? result : [];
    } catch (error) {
        console.error('searchCustomer error:', error.message);
        return [];
    }
}

/**
 * Get customer count grouped by status
 * @returns {Promise<Array>} - Array of status count objects
 */
async function getSummary() {
    try {
        const result = await callPythonFunction('getSummary');
        return Array.isArray(result) ? result : [];
    } catch (error) {
        console.error('getSummary error:', error.message);
        return [];
    }
}

/**
 * Count customers matching search query
 * @param {string} query - Search term
 * @returns {Promise<number>} - Count of matching customers
 */
async function getSearchCount(query) {
    try {
        const result = await callPythonFunction('getSearchCount', { query });
        return typeof result === 'number' ? result : 0;
    } catch (error) {
        console.error('getSearchCount error:', error.message);
        return 0;
    }
}

/**
 * Execute a read-only SQL query with security checks
 * @param {string} sql - SELECT SQL query to execute
 * @returns {Promise<Array|Object>} - Query results or error object
 */
async function executeReadOnlyQuery(sql) {
    try {
        const result = await callPythonFunction('executeReadOnlyQuery', { sql });
        return result;
    } catch (error) {
        console.error('executeReadOnlyQuery error:', error.message);
        return { error: error.message };
    }
}

// Export functions with same API as original
module.exports = {
    getCustomerByPhone,
    searchCustomer,
    getSummary,
    getSearchCount,
    testConnection,
    executeReadOnlyQuery,
};