#!/usr/bin/env node
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// CRITICAL: Load Windows certificates FIRST to enable corporate network support
// win-ca loads certificates from Windows Trusted Root Certificate Store into Node.js
require("win-ca/fallback");
// CRITICAL: Bootstrap global-agent SECOND to enable proxy support for ALL network calls
// This MUST be imported and executed before ANY other imports that use fetch/http/https
const global_agent_1 = require("global-agent");
(0, global_agent_1.bootstrap)();
// Load environment variables THIRD (before any other imports that might use them)
const dotenv = __importStar(require("dotenv"));
dotenv.config();
/**
 * RepairIQ Sync Agent v1.3.7
 *
 * Desktop companion app that watches a local folder for CCC ONE EMS exports
 * and automatically uploads them to RepairIQ.
 *
 * Features:
 * - ONE-CLICK INSTALLER: Auto-installs Node.js if needed
 * - Automatic file watching and upload
 * - Windows Service support
 * - Enterprise auto-update via Scheduled Task (SYSTEM privileges)
 * - SHA256 verification and automatic rollback
 * - Service/Standalone mode detection
 * - System proxy auto-detection (PAC/WPAD)
 * - Windows certificate store integration (win-ca)
 * - Excel dual-feed: Write customer data to local Excel file (uses API-parsed data)
 */
const chokidar = __importStar(require("chokidar"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const node_fetch_1 = __importDefault(require("node-fetch"));
const form_data_1 = __importDefault(require("form-data"));
const logger_1 = require("./logger");
const auto_updater_1 = require("./auto-updater");
const excel_writer_1 = require("./excel-writer");
// PRODUCTION CONFIGURATION - DO NOT MODIFY
// These values are hardcoded for production Windows Service deployment
const API_URL = 'https://www.repairiq.app'; // Production API - use www to avoid redirect
const WATCH_FOLDER = 'C:\\RepairIQ-EMS';
const PROCESSED_FOLDER = path.join(WATCH_FOLDER, 'Processed');
const COMPANY_ID = 'default';
const WAIT_TIME = 5000; // Wait 5 seconds for files to finish writing
// Track processing state
const processingFiles = new Map();
/**
 * Ensure required folders exist
 */
function ensureFolders() {
    if (!fs.existsSync(WATCH_FOLDER)) {
        fs.mkdirSync(WATCH_FOLDER, { recursive: true });
        (0, logger_1.log)(`Created watch folder: ${WATCH_FOLDER}`);
    }
    if (!fs.existsSync(PROCESSED_FOLDER)) {
        fs.mkdirSync(PROCESSED_FOLDER, { recursive: true });
        (0, logger_1.log)(`Created processed folder: ${PROCESSED_FOLDER}`);
    }
}
/**
 * Get all files with the same base name
 */
function getFileGroup(baseName) {
    const files = [];
    try {
        const allFiles = fs.readdirSync(WATCH_FOLDER);
        for (const file of allFiles) {
            if (file.startsWith(baseName) && file !== `${baseName}`) {
                const fullPath = path.join(WATCH_FOLDER, file);
                // Only include if it's a file (not a directory)
                if (fs.statSync(fullPath).isFile()) {
                    files.push(fullPath);
                }
            }
        }
    }
    catch (error) {
        (0, logger_1.log)(`Error reading file group for ${baseName}: ${error}`, 'ERROR');
    }
    return files;
}
/**
 * Upload file group to RepairIQ API
 * Returns the full API response including customerData for Excel writing
 */
async function uploadFileGroup(baseName, files) {
    try {
        (0, logger_1.log)(`Uploading ${files.length} files for ${baseName}...`);
        // Create form data
        const form = new form_data_1.default();
        form.append('companyId', COMPANY_ID);
        form.append('baseName', baseName);
        // Add all files
        for (const filePath of files) {
            const fileName = path.basename(filePath);
            const fileStream = fs.createReadStream(filePath);
            form.append('files', fileStream, fileName);
        }
        // Upload to API
        const response = await (0, node_fetch_1.default)(`${API_URL}/api/integration/ems-upload`, {
            method: 'POST',
            body: form,
            redirect: 'follow', // Follow redirects automatically
            headers: form.getHeaders(),
            timeout: 120000, // 2 minute timeout
        });
        // Check if we got redirected to an error page (HTML instead of JSON)
        const contentType = response.headers.get('content-type') || '';
        if (contentType.includes('text/html')) {
            const htmlBody = await response.text();
            (0, logger_1.log)(`❌ API returned HTML instead of JSON - possible redirect or error page`, 'ERROR');
            (0, logger_1.log)(`   Status: ${response.status}`, 'ERROR');
            (0, logger_1.log)(`   URL: ${response.url}`, 'ERROR');
            (0, logger_1.log)(`   Body preview: ${htmlBody.substring(0, 200)}...`, 'ERROR');
            return null;
        }
        const data = await response.json();
        if (data.success) {
            (0, logger_1.log)(`✅ Successfully uploaded ${baseName}`);
            (0, logger_1.log)(`   Vehicle ID: ${data.vehicleId || 'N/A'}`);
            (0, logger_1.log)(`   Estimate ID: ${data.estimateId || 'N/A'}`);
            if (data.customerData) {
                (0, logger_1.log)(`   Customer: ${data.customerData.name || 'N/A'}`);
                (0, logger_1.log)(`   VIN: ${data.customerData.vin || 'N/A'}`);
            }
            return data;
        }
        else {
            (0, logger_1.log)(`❌ Upload failed for ${baseName}: ${data.error}`, 'ERROR');
            return null;
        }
    }
    catch (error) {
        (0, logger_1.log)(`❌ Upload error for ${baseName}: ${error.message}`, 'ERROR');
        return null;
    }
}
/**
 * Move files to processed folder
 */
function moveToProcessed(files) {
    for (const filePath of files) {
        try {
            const fileName = path.basename(filePath);
            const destPath = path.join(PROCESSED_FOLDER, fileName);
            fs.renameSync(filePath, destPath);
            (0, logger_1.log)(`Moved to processed: ${fileName}`);
        }
        catch (error) {
            (0, logger_1.log)(`Failed to move ${filePath}: ${error}`, 'ERROR');
        }
    }
}
/**
 * Process a file group
 */
async function processFileGroup(baseName) {
    try {
        (0, logger_1.log)(`Processing file group: ${baseName}`);
        // Get all files in the group
        const files = getFileGroup(baseName);
        if (files.length === 0) {
            (0, logger_1.log)(`No files found for ${baseName}`, 'WARN');
            return;
        }
        (0, logger_1.log)(`Found ${files.length} files:`);
        files.forEach(f => (0, logger_1.log)(`  - ${path.basename(f)}`));
        // Upload to API (returns customerData parsed by the API)
        const uploadResult = await uploadFileGroup(baseName, files);
        if (uploadResult && uploadResult.success) {
            // Write to Excel using customerData from API response (v1.2.1+)
            if ((0, excel_writer_1.isExcelEnabled)() && uploadResult.customerData) {
                const excelData = {
                    customerName: uploadResult.customerData.name || '',
                    phone: uploadResult.customerData.phone || '',
                    email: uploadResult.customerData.email || '',
                    year: uploadResult.customerData.year || '',
                    make: uploadResult.customerData.make || '',
                    model: uploadResult.customerData.model || '',
                    vin: uploadResult.customerData.vin || '',
                    color: uploadResult.customerData.color || '',
                    licensePlate: uploadResult.customerData.licensePlate || '',
                    insuranceCompany: uploadResult.customerData.insurance || '',
                    checkInDate: uploadResult.customerData.checkInDate || new Date().toLocaleDateString(),
                };
                // Only write if we have VIN or customer name
                if (excelData.vin || excelData.customerName) {
                    (0, logger_1.log)(`Excel: Writing data for ${excelData.customerName || excelData.vin}`);
                    (0, excel_writer_1.writeToExcel)(excelData);
                }
                else {
                    (0, logger_1.log)(`Excel: Skipping - no VIN or customer name in API response`, 'WARN');
                }
            }
            // Move to processed folder
            moveToProcessed(files);
            (0, logger_1.log)(`✅ Completed processing ${baseName}`);
        }
        else {
            (0, logger_1.log)(`❌ Failed to process ${baseName}`, 'ERROR');
        }
    }
    catch (error) {
        (0, logger_1.log)(`❌ Error processing ${baseName}: ${error}`, 'ERROR');
    }
}
/**
 * Handle new file detected
 */
function handleNewFile(filePath) {
    try {
        const fileName = path.basename(filePath);
        const ext = path.extname(fileName).toLowerCase();
        // Only process .veh files as triggers
        if (ext !== '.veh') {
            return;
        }
        const baseName = fileName.replace(/\.veh$/i, '');
        (0, logger_1.log)(`Detected new .veh file: ${fileName}`);
        // Cancel any existing timer for this base name
        if (processingFiles.has(baseName)) {
            clearTimeout(processingFiles.get(baseName));
            (0, logger_1.log)(`Reset timer for ${baseName}`);
        }
        // Wait for all files to finish writing
        const timer = setTimeout(() => {
            (0, logger_1.log)(`Wait period complete for ${baseName}, starting upload...`);
            processingFiles.delete(baseName);
            processFileGroup(baseName);
        }, WAIT_TIME);
        processingFiles.set(baseName, timer);
        (0, logger_1.log)(`Waiting ${WAIT_TIME}ms for all ${baseName} files to finish writing...`);
    }
    catch (error) {
        (0, logger_1.log)(`Error handling file ${filePath}: ${error}`, 'ERROR');
    }
}
/**
 * Start watching folder
 */
function startWatching() {
    // Initialize logger
    (0, logger_1.initLogger)();
    // Log startup information
    (0, logger_1.log)('=====================================');
    (0, logger_1.log)(`RepairIQ Sync Agent v${(0, auto_updater_1.getCurrentVersion)()}`);
    (0, logger_1.log)(`Mode: ${(0, logger_1.isService)() ? 'Windows Service' : 'Standalone'}`);
    (0, logger_1.log)('=====================================');
    (0, logger_1.log)(`Watch folder: ${WATCH_FOLDER}`);
    (0, logger_1.log)(`Processed folder: ${PROCESSED_FOLDER}`);
    (0, logger_1.log)(`API URL: ${API_URL}`);
    (0, logger_1.log)(`Company ID: ${COMPANY_ID}`);
    (0, logger_1.log)(`Wait time: ${WAIT_TIME}ms`);
    (0, logger_1.log)('-------------------------------------');
    (0, logger_1.log)('Proxy: System auto-detection enabled');
    (0, logger_1.log)(`  HTTP_PROXY: ${process.env.GLOBAL_AGENT_HTTP_PROXY || process.env.HTTP_PROXY || 'auto-detect'}`);
    (0, logger_1.log)(`  HTTPS_PROXY: ${process.env.GLOBAL_AGENT_HTTPS_PROXY || process.env.HTTPS_PROXY || 'auto-detect'}`);
    (0, logger_1.log)('=====================================');
    // Ensure folders exist
    ensureFolders();
    // Initialize Excel writer (if enabled)
    (0, excel_writer_1.initExcelWriter)();
    // Start auto-updater (checks for updates every 6 hours - enterprise mode)
    (0, auto_updater_1.startAutoUpdater)(API_URL);
    // Start watching
    const watcher = chokidar.watch(WATCH_FOLDER, {
        ignored: [
            PROCESSED_FOLDER, // Ignore processed folder
            path.join(WATCH_FOLDER, 'logs'), // Ignore logs folder
            /(^|[\/\\])\../, // Ignore dotfiles
        ],
        persistent: true,
        ignoreInitial: false, // Process existing files on startup
        awaitWriteFinish: {
            stabilityThreshold: 2000,
            pollInterval: 100,
        },
    });
    watcher
        .on('add', (filePath) => {
        handleNewFile(filePath);
    })
        .on('change', (filePath) => {
        // File changed, reset timer
        const fileName = path.basename(filePath);
        const ext = path.extname(fileName).toLowerCase();
        if (ext === '.veh') {
            handleNewFile(filePath);
        }
    })
        .on('error', (error) => {
        (0, logger_1.log)(`Watcher error: ${error}`, 'ERROR');
    })
        .on('ready', () => {
        (0, logger_1.log)('✅ Watching for new EMS files...');
    });
    // Handle process termination
    process.on('SIGINT', () => {
        (0, logger_1.log)('Shutting down...');
        (0, excel_writer_1.stopRetryProcessor)();
        watcher.close();
        process.exit(0);
    });
    process.on('SIGTERM', () => {
        (0, logger_1.log)('Shutting down...');
        (0, excel_writer_1.stopRetryProcessor)();
        watcher.close();
        process.exit(0);
    });
}
// Start the agent
startWatching();
//# sourceMappingURL=index.js.map