<?php

/**
 * conductor.php
 *
 * The main CLI entry point.
 */
error_reporting(E_ERROR | E_PARSE);

// Disable persistent DB connections for CLI scripts that touch many databases.
// Conductor iterates through all 400+ stores, so persistent connections would
// accumulate and exhaust the MySQL connection pool.
define('TASKENGINE_WORKER_CONTEXT', true);

require_once __DIR__ . '/initialize.php';  // If this sets up DB connections, logging, etc.

// Example: if you use KLogger, create a logger instance
$logger = new \KLogger(__DIR__ . '/../logs/conductor.log', \KLogger::DEBUG);

$command = $argv[1] ?? null;

switch ($command) {
    case 'run':
        // Check for --fresh flag (clears migration log before running)
        $freshMode = in_array('--fresh', $argv);

        if ($freshMode) {
            echo "Fresh mode enabled - clearing migration log...\n";
            try {
                $db = dbConnectByName($_ENV['DB_NAME']);
                $countStmt = $db->query("SELECT COUNT(*) as cnt FROM migration_log");
                $count = $countStmt->fetch(PDO::FETCH_ASSOC)['cnt'];

                $db->exec("TRUNCATE TABLE migration_log");
                echo "Cleared {$count} migration log entries.\n";
                echo "Migrations will now rely on check_query to determine if they need to run.\n\n";
                $logger->LogInfo("Fresh mode: Cleared {$count} migration log entries");
            } catch (PDOException $e) {
                echo "Warning: Could not clear migration log: " . $e->getMessage() . "\n";
                $logger->LogError("Failed to clear migration log: " . $e->getMessage());
            }
        }

        echo "Starting migrations...\n";

        // Include (or require) the migration logic
        require_once __DIR__ . '/migrations/migrate.php';

        // Actually run all migrations, gathering results
        $results = runAllMigrations();

        // Print and/or log the results in a user-friendly way
        printAndLogMigrationResults($results);
        echo "Migrations complete.\n";
        break;

    case 'create-store':
        // A hypothetical command to create a new store DB
        $storeName = $argv[2] ?? '';
        if (!$storeName) {
            echo "Usage: php conductor.php create-store <STORE_DB_NAME>\n";
            exit(1);
        }
        // Example call to some function in storeMigration.php (not shown)
        // require_once __DIR__ . '/storeMigration.php';
        // createNewStore($storeName);

        echo "Store creation logic not fully implemented.\n";
        break;
    case 'store-dirs':
         storeDirectories();
         break;
    case 'sign-in-log':
        getSignInLogAverages();
        break;
    case 'sync_store':
        syncStore($argv);
        break;
    case 'setup-store':
        setupStore($argv);
        break;
    case 'migrate-store':
        migrateStoreNumber($argv);
        break;
    case 'build-css':
        buildAdminThemeCss($argv);
        break;
    case 'delete-customer-data':
        deleteCustomerData($argv);
        break;
    case 'list-deletion-requests':
        listDeletionRequests($argv);
        break;
    case 'copy-sales':
        copySalesData($argv);
        break;
    default:
        echo "Usage:\n";
        echo "  php conductor.php run [--fresh]\n";
        echo "      --fresh  Clear migration log before running (use after production DB sync)\n";
        echo "  php conductor.php create-store <STORE_DB_NAME>\n";
        echo "  php conductor.php sync_store <source_store> <destination_store> [--full]\n";
        echo "  php conductor.php setup-store <store_number>\n";
        echo "  php conductor.php build-css [--minify] [--watch]\n";
        echo "  php conductor.php migrate-store <old_typeNum> <new_typeNum> [--execute]\n";
        echo "  php conductor.php delete-customer-data <phone_number> [--dry-run]\n";
        echo "  php conductor.php list-deletion-requests [--status=pending]\n";
        echo "  php conductor.php copy-sales <source_typeNum> <dest_typeNum>\n";
        exit(0);
}

/**
 * Print and optionally log the migration results.
 * Adjust to match how your $results array is structured.
 */
function printAndLogMigrationResults(array $results)
{
    // If you have a globals or an injected $logger, you could do:
    global $logger;

    // Were there any actual migrations processed?
    $skippedMigrations = $results['skipped_migrations'] ?? [];
    if (empty($results['success']) && empty($skippedMigrations) && empty($results['error'])) {
        echo "No migrations found or nothing to process.\n";
        $logger->LogInfo("No migrations found or nothing to process.");
        return;
    }

    echo "\n";
    echo str_repeat("=", 50) . "\n";
    echo "Migration Summary\n";
    echo str_repeat("=", 50) . "\n";

    // Print success items
    if (!empty($results['success'])) {
        echo "\nSuccessfully Applied (" . count($results['success']) . " operations):\n";
        foreach ($results['success'] as $success) {
            $db   = $success['database']    ?? '[unknown DB]';
            $op   = $success['operation']   ?? '[unknown operation]';
            $desc = $success['description'] ?? 'N/A';

            echo "  [SUCCESS] $db | $op | $desc\n";
            $logger->LogInfo("SUCCESS: $db | $op | $desc");
        }
    } else {
        echo "\nNo new migrations applied.\n";
    }

    // Print skipped count (not individual items)
    if (!empty($skippedMigrations)) {
        $count = count($skippedMigrations);
        echo "\nSkipped: $count migration(s) already applied\n";
        $logger->LogInfo("Skipped $count migration(s) - already applied");
    }

    // Print errors
    if (!empty($results['error'])) {
        echo "\nErrors (" . count($results['error']) . "):\n";
        foreach ($results['error'] as $errorItem) {
            $db   = $errorItem['database']  ?? '[unknown DB]';
            $op   = $errorItem['operation'] ?? '[unknown operation]';
            $msg  = $errorItem['error']     ?? 'N/A';
            $file = $errorItem['file']      ?? '';

            $fileInfo = $file ? " [file: $file]" : '';
            echo "  [ERROR] $db | $op | $msg$fileInfo\n";
            $logger->LogError("ERROR: $db | $op | $msg$fileInfo");
        }
    }

    echo str_repeat("=", 50) . "\n\n";
}

function storeDirectories() {
    $stores = getAllStoresData(1,0);
    foreach ($stores as $store) {
        echo "Store: ".$store->getTypeNum()." \n";
        $dir = $_ENV['LOG_DIR']."stores/";
        $dir .= $store->getTypeNum()."/";
        if(!file_exists($dir)) {
            mkdir($dir, 0775);
            echo "Made: ".$dir." \n";
        }
        $twilio = $dir."twilio_log.txt";
        if(!file_exists($twilio)) {
            fopen($twilio, "w+");
            echo "Made TWILIO_LOG \n";
        }
        $api = $dir."api_log.txt";
        if(!file_exists($api)) {
            fopen($api, "w+");
            echo "Made API_LOG \n";
        }
        $loyalty = $dir."loyalty_log.txt";
        if(!file_exists($loyalty)) {
            fopen($loyalty, "w+");
            echo "Made LOYALTY_LOG \n";
        }
        $dir = $_ENV['HOME_DIR']."public_html/upload/digitalSign/";
        $dir .= $store->getTypeNum()."/";
        if(!file_exists($dir)) {
            mkdir($dir, 0775);
            echo "Made: ".$dir." \n";
        }
        $thumbs = $dir."thumbs";
        if(!file_exists($thumbs)) {
            mkdir($thumbs, 0775);
            echo "Made: ".$thumbs." \n";
        }
        $small = $dir."thumbs/small";
        if(!file_exists($small)) {
            mkdir($small, 0775);
            echo "Made: ".$small." \n";
        }
        $dir = $_ENV['HOME_DIR']."public_html/upload/shopify/";
        $dir .= $store->getTypeNum()."/";
        if(!file_exists($dir)) {
            mkdir($dir, 0775);
            echo "Made: ".$dir." \n";
        }
        $dir = $_ENV['HOME_DIR']."userfrosting/upload/s-files/".$store->getTypeNum()."/";;
        if(!file_exists($dir)) {
            mkdir($dir, 0775);
            echo "Made: ".$dir." \n";
        }
        $dir = $_ENV['HOME_DIR']."public_html/upload/resaleperks/";
        if(!file_exists($dir)) {
            mkdir($dir, 0775);
            echo "Made: ".$dir." \n";
        }
        $dir .= $store->getTypeNum()."/";
        if(!file_exists($dir)) {
            mkdir($dir, 0775);
            echo "Made: ".$dir." \n";
        }
        $dir = $_ENV['HOME_DIR']."invoices/";
        $dir .= $store->getTypeNum()."/";
        if(!file_exists($dir)) {
            mkdir($dir, 0775);
            echo "Made: ".$dir." \n";
        }
    }
}

function getSignInLogAverages() {
    $db = dbConnectByName('kiosk_buykiosk');

// Set a reasonable batch size
    $batchSize = 100000;
    $totalRecords = $db->query("SELECT COUNT(*) FROM signInLog")->fetchColumn();
    $batches = ceil($totalRecords / $batchSize);

// Initialize aggregation variables
    $stats = [
        0 => ['info_sum' => 0, 'question_sum' => 0, 'count' => 0],
        1 => ['info_sum' => 0, 'question_sum' => 0, 'count' => 0]
    ];

// Process in batches
    for ($i = 0; $i < $batches; $i++) {
        $offset = $i * $batchSize;

        $query = "SELECT 
        wasNewCustomer,
        SUM(infoTime) as info_sum,
        SUM(questionTime) as question_sum,
        COUNT(*) as count
    FROM signInLog 
    GROUP BY wasNewCustomer
    LIMIT {$batchSize} OFFSET {$offset}";

        $result = $db->query($query);

        while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
            $type = $row['wasNewCustomer'];
            $stats[$type]['info_sum'] += $row['info_sum'];
            $stats[$type]['question_sum'] += $row['question_sum'];
            $stats[$type]['count'] += $row['count'];
        }
    }

// Calculate final averages
    foreach ([0, 1] as $type) {
        $customerType = $type ? "New Customers" : "Existing Customers";
        $count = $stats[$type]['count'];

        if ($count > 0) {
            $avgInfo = $stats[$type]['info_sum'] / $count;
            $avgQuestion = $stats[$type]['question_sum'] / $count;
            $avgTotal = ($stats[$type]['info_sum'] + $stats[$type]['question_sum']) / $count;

            echo "\n{$customerType}:\n";
            echo "Average Info Time: " . number_format($avgInfo, 2) . " seconds\n";
            echo "Average Question Time: " . number_format($avgQuestion, 2) . " seconds\n";
            echo "Average Total Time: " . number_format($avgTotal, 2) . " seconds\n";
            echo "Total Customers: " . number_format($count) . "\n";
        }
    }

// Calculate time difference
    $newAvg = ($stats[1]['info_sum'] + $stats[1]['question_sum']) / $stats[1]['count'];
    $existingAvg = ($stats[0]['info_sum'] + $stats[0]['question_sum']) / $stats[0]['count'];
    $difference = $newAvg - $existingAvg;

    echo "\nTime Difference Analysis:\n";
    echo "Time difference between new and existing customers: " .
        number_format($difference, 2) . " seconds\n";


}

function syncStore($argv) {
    global $logger;
    
    // Parse arguments
    $sourceStore = $argv[2] ?? null;
    $destStore = $argv[3] ?? null;
    $fullSync = in_array('--full', $argv);
    
    if (!$sourceStore || !$destStore) {
        echo "Usage: php conductor.php sync_store <source_store> <destination_store> [--full]\n";
        echo "Example: php conductor.php sync_store pc80718 pc00\n";
        echo "Options:\n";
        echo "  --full  : Perform a full database copy (wipe destination and replace with source)\n";
        exit(1);
    }
    
    echo "Starting sync from $sourceStore to $destStore...\n";
    $logger->LogInfo("Starting sync from $sourceStore to $destStore (full: " . ($fullSync ? 'yes' : 'no') . ")");
    
    // Tables to sync based on the SQL file
    $tablesToSync = [
        'buyQueue',
        'customerAlerts',
        'customerRatings',
        'customers',
        'customerSurvey',
        'employees',
        'shiftNotes',
        'statsEmployeeDaily',
        'statsStoreDaily'
    ];
    
    try {
        // Connect to both databases
        $sourceDb = dbConnectByName('kiosk_' . $sourceStore);
        $destDb = dbConnectByName('kiosk_' . $destStore);
        
        if (!$sourceDb || !$destDb) {
            throw new Exception("Failed to connect to one or both databases");
        }
        
        // Begin transaction on destination
        $destDb->beginTransaction();
        
        foreach ($tablesToSync as $table) {
            echo "Syncing table: $table\n";
            
            if ($fullSync) {
                // Full sync: truncate destination table and copy all data
                $destDb->exec("TRUNCATE TABLE `$table`");
                
                // Get all data from source
                $stmt = $sourceDb->query("SELECT * FROM `$table`");
                $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
                
                if (count($rows) > 0) {
                    // Prepare insert statement
                    $columns = array_keys($rows[0]);
                    $columnStr = '`' . implode('`, `', $columns) . '`';
                    $placeholders = ':' . implode(', :', $columns);
                    
                    $insertStmt = $destDb->prepare("INSERT INTO `$table` ($columnStr) VALUES ($placeholders)");
                    
                    foreach ($rows as $row) {
                        // Obfuscate customer data if this is the customers table
                        if ($table === 'customers') {
                            $row = obfuscateCustomerRow($row);
                        }
                        
                        $insertStmt->execute($row);
                    }
                }
                
                echo "  - Copied " . count($rows) . " rows\n";
                
            } else {
                // Incremental sync: only sync recent changes (last 7 days)
                $dateColumn = getDateColumnForTable($table);
                
                if ($dateColumn) {
                    // Sync records from the last 90 days
                    $sevenDaysAgo = date('Y-m-d H:i:s', strtotime('-90 days'));
                    
                    $stmt = $sourceDb->prepare("SELECT * FROM `$table` WHERE `$dateColumn` >= :date");
                    $stmt->execute(['date' => $sevenDaysAgo]);
                    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
                    
                    if (count($rows) > 0) {
                        $columns = array_keys($rows[0]);
                        $columnStr = '`' . implode('`, `', $columns) . '`';
                        $placeholders = ':' . implode(', :', $columns);
                        $updateStr = implode(', ', array_map(function($col) {
                            return "`$col` = VALUES(`$col`)";
                        }, $columns));
                        
                        // Use INSERT ... ON DUPLICATE KEY UPDATE for incremental sync
                        $insertStmt = $destDb->prepare("
                            INSERT INTO `$table` ($columnStr) 
                            VALUES ($placeholders)
                            ON DUPLICATE KEY UPDATE $updateStr
                        ");
                        
                        foreach ($rows as $row) {
                            // Obfuscate customer data if this is the customers table
                            if ($table === 'customers') {
                                $row = obfuscateCustomerRow($row);
                            }
                            
                            $insertStmt->execute($row);
                        }
                    }
                    
                    echo "  - Synced " . count($rows) . " recent rows\n";
                } else {
                    echo "  - Skipping incremental sync for $table (no date column)\n";
                }
            }
        }
        
        // Commit transaction
        $destDb->commit();
        
        echo "\nSync completed successfully!\n";
        $logger->LogInfo("Sync from $sourceStore to $destStore completed successfully");
        
        // Run obfuscation on the destination store if it's a demo store
        if (strpos($destStore, '00') !== false) {
            echo "Running additional obfuscation on demo store...\n";
            obfuscateCustomerData($destStore);
            echo "Obfuscation completed.\n";
        }
        
    } catch (Exception $e) {
        if (isset($destDb) && $destDb->inTransaction()) {
            $destDb->rollBack();
        }
        
        echo "Error during sync: " . $e->getMessage() . "\n";
        $logger->LogError("Sync failed: " . $e->getMessage());
        exit(1);
    }
}

function getDateColumnForTable($table) {
    // Return the appropriate date column for each table
    $dateColumns = [
        'buyQueue' => 'timeEntered',
        'customerAlerts' => 'dateAdded',
        'customers' => 'dateAdded',
        'customerSurvey' => 'dateSubmitted',
        'shiftNotes' => 'timeStamp',
        'statsEmployeeDaily' => 'date',
        'statsStoreDaily' => 'date'
    ];
    
    return $dateColumns[$table] ?? null;
}

function obfuscateCustomerRow($row) {
    // Obfuscate sensitive customer data
    if (isset($row['phone'])) {
        $row['phone'] = obfuscateDigits($row['phone']);
    }
    if (isset($row['driversLicense'])) {
        $row['driversLicense'] = obfuscateDigits($row['driversLicense']);
    }
    if (isset($row['email'])) {
        $row['email'] = obfuscateEmail($row['email']);
    }
    if (isset($row['address'])) {
        $row['address'] = '101 Main Street';
    }
    if (isset($row['firstName'])) {
        $row['firstName'] = 'Test' . substr($row['firstName'], 0, 1);
    }
    if (isset($row['lastName'])) {
        $row['lastName'] = 'User' . substr($row['lastName'], 0, 1);
    }
    
    return $row;
}

/**
 * Store setup function - creates new stores from a quoteRequests record
 */
function setupStore($argv) {
    global $logger;

    // Parse --quote-id=N from arguments
    $quoteId = null;
    $isPhase2 = false;
    $sendRealEmail = false;

    foreach (array_slice($argv, 2) as $arg) {
        if (str_starts_with($arg, '--quote-id=')) {
            $quoteId = (int) substr($arg, strlen('--quote-id='));
        } elseif ($arg === '--phase2' || $arg === '--live') {
            $isPhase2 = true;
        } elseif ($arg === '--send-email') {
            $sendRealEmail = true;
        }
    }

    if (!$quoteId) {
        echo "Usage: php conductor setup-store --quote-id=<ID> [--phase2] [--send-email]\n";
        echo "Example: php conductor setup-store --quote-id=42                         (Phase 1 - validation only)\n";
        echo "Example: php conductor setup-store --quote-id=42 --phase2                (Phase 2 - test email to admin)\n";
        echo "Example: php conductor setup-store --quote-id=42 --phase2 --send-email   (Phase 2 - real email to owner)\n";
        echo "\nPhase 1 (Default):\n";
        echo "  1. Load quote data from quoteRequests table\n";
        echo "  2. Calculate store configuration (typeNum, database name, etc.)\n";
        echo "  3. Generate user accounts and passwords\n";
        echo "  4. Display all data to console for validation\n";
        echo "  5. Preview email content (no actual email sent)\n";
        echo "\nPhase 2 (--phase2 flag):\n";
        echo "  1. All Phase 1 operations\n";
        echo "  2. Create actual database records\n";
        echo "  3. Send test email to admin@buyerkiosk.com\n";
        echo "  4. Update quote status to 'won'\n";
        echo "\nFlags:\n";
        echo "  --send-email: Send welcome email to actual owner (use with --phase2)\n";
        exit(1);
    }

    try {
        echo "BuyerKiosk Store Setup - Starting process for quote #$quoteId\n";
        $logger->LogInfo("Store setup initiated for quote #$quoteId");

        // Initialize the StoreSetupService
        require_once __DIR__ . '/services/StoreSetupService.php';

        $setupService = new \UserFrosting\Services\StoreSetupService();

        // Run store setup (Phase 1 or 2 based on flag)
        $success = $setupService->setupStoreFromQuote($quoteId, $isPhase2, $sendRealEmail);

        if ($success) {
            echo "\n" . str_repeat("=", 60) . "\n";
            if ($isPhase2) {
                echo "PHASE 2 COMPLETE: Store setup successful!\n";
                echo "Quote #$quoteId has been processed.\n";
                echo "\nWhat was created:\n";
                echo "  ✓ Store database and records\n";
                echo "  ✓ User accounts with login credentials\n";
                echo "  ✓ Group assignments and permissions\n";
                if ($sendRealEmail) {
                    echo "  ✓ Welcome email sent to store owner\n";
                } else {
                    echo "  ✓ Test email sent to admin@buyerkiosk.com\n";
                }
                echo "  ✓ Quote status updated to 'won'\n";
                $logger->LogInfo("Store setup Phase 2 completed successfully for quote #$quoteId");
            } else {
                echo "PHASE 1 COMPLETE: Data validation successful!\n";
                echo "Review the above information carefully.\n";
                echo "\nNext Steps:\n";
                echo "  1. Verify all quote data is correct\n";
                echo "  2. Confirm calculated values (typeNum, database name, etc.)\n";
                echo "  3. Check generated usernames and passwords\n";
                echo "  4. Run with --phase2 flag to perform actual database operations\n";
                $logger->LogInfo("Store setup Phase 1 completed successfully for quote #$quoteId");
            }
            echo str_repeat("=", 60) . "\n";
        } else {
            echo "\nStore setup failed. Check error messages above and logs for details.\n";
            $logger->LogError("Store setup failed for quote #$quoteId");
            exit(1);
        }

    } catch (Exception $e) {
        echo "FATAL ERROR: " . $e->getMessage() . "\n";
        $logger->LogError("Fatal error in store setup for quote #$quoteId: " . $e->getMessage());
        exit(1);
    }
}

/**
 * Build Admin Theme CSS
 *
 * Concatenates and optionally minifies CSS files from the admin theme directory.
 * File order: tokens.css → admin-theme.css → modules/*.css → vendor/*.css
 *
 * Usage:
 *   php conductor.php build-css            # Development build
 *   php conductor.php build-css --minify   # Production build (minified)
 *   php conductor.php build-css --watch    # Watch mode with auto-rebuild
 *
 * @param array $argv Command line arguments
 */
function buildAdminThemeCss($argv) {
    global $logger;

    // Parse flags
    $minify = in_array('--minify', $argv);
    $watch = in_array('--watch', $argv);

    // Define paths (relative to project root, which is parent of userfrosting/)
    $projectRoot = dirname(__DIR__);
    $adminCssDir = $projectRoot . '/public_html/css/admin';
    $outputFile = $adminCssDir . '/admin-theme.min.css';
    $versionFile = $adminCssDir . '/version.txt';

    // Size limit (500KB = 512000 bytes) - increased to accommodate growing module CSS
    $maxBundleSize = 512000;

    echo "🎨 BuyerKiosk Admin Theme CSS Builder\n";
    echo str_repeat("-", 50) . "\n";

    if ($watch) {
        echo "👀 Watch mode enabled. Press Ctrl+C to stop.\n\n";
        $lastHash = '';

        while (true) {
            $currentHash = getSourceFilesHash($adminCssDir);

            if ($currentHash !== $lastHash) {
                $lastHash = $currentHash;
                echo "\n📝 Change detected, rebuilding...\n";
                $result = performCssBuild($adminCssDir, $outputFile, $versionFile, $minify, $maxBundleSize, $logger);

                if (!$result['success']) {
                    echo "❌ Build failed: " . $result['error'] . "\n";
                }
            }

            sleep(1); // Poll every second
        }
    } else {
        $result = performCssBuild($adminCssDir, $outputFile, $versionFile, $minify, $maxBundleSize, $logger);

        if ($result['success']) {
            echo "\n✅ Build complete!\n";
            exit(0);
        } else {
            echo "\n❌ Build failed: " . $result['error'] . "\n";
            exit(1);
        }
    }
}

/**
 * Get a hash of all source CSS files to detect changes
 */
function getSourceFilesHash($adminCssDir) {
    $files = getCssSourceFiles($adminCssDir);
    $contents = '';

    foreach ($files as $file) {
        if (file_exists($file)) {
            $contents .= filemtime($file);
        }
    }

    return md5($contents);
}

/**
 * Get ordered list of CSS source files
 */
function getCssSourceFiles($adminCssDir) {
    $files = [];

    // 1. tokens.css (must be first - defines all CSS variables)
    $tokensFile = $adminCssDir . '/tokens.css';
    if (file_exists($tokensFile)) {
        $files[] = $tokensFile;
    }

    // 2. admin-theme.css (component customizations)
    $themeFile = $adminCssDir . '/admin-theme.css';
    if (file_exists($themeFile)) {
        $files[] = $themeFile;
    }

    // 3. modules/*.css (page-specific styles, sorted alphabetically)
    $modulesDir = $adminCssDir . '/modules';
    if (is_dir($modulesDir)) {
        $moduleFiles = glob($modulesDir . '/*.css') ?: [];
        sort($moduleFiles);
        $files = array_merge($files, $moduleFiles);
    }

    // 4. vendor/*.css (third-party integration styles, sorted alphabetically)
    $vendorDir = $adminCssDir . '/vendor';
    if (is_dir($vendorDir)) {
        $vendorFiles = glob($vendorDir . '/*.css') ?: [];
        sort($vendorFiles);
        $files = array_merge($files, $vendorFiles);
    }

    return $files;
}

/**
 * Perform the actual CSS build
 */
function performCssBuild($adminCssDir, $outputFile, $versionFile, $minify, $maxBundleSize, $logger) {
    $startTime = microtime(true);

    // Get source files
    $files = getCssSourceFiles($adminCssDir);

    if (empty($files)) {
        return [
            'success' => false,
            'error' => 'No CSS source files found in ' . $adminCssDir
        ];
    }

    echo "📂 Source files:\n";
    foreach ($files as $file) {
        $relativePath = str_replace(dirname(dirname($adminCssDir)) . '/', '', $file);
        $size = filesize($file);
        echo "   • $relativePath (" . formatBytes($size) . ")\n";
    }

    // Concatenate all files
    $combined = "/**\n * BuyerKiosk Admin Theme Bundle\n * Generated: " . date('Y-m-d H:i:s') . "\n * Files: " . count($files) . "\n */\n\n";

    foreach ($files as $file) {
        $fileName = basename($file);
        $content = file_get_contents($file);
        $combined .= "/* ========== $fileName ========== */\n";
        $combined .= $content . "\n\n";
    }

    // Minify if requested
    if ($minify) {
        echo "\n🗜️  Minifying CSS...\n";
        $combined = minifyCss($combined);
    }

    // Write output file
    $bytesWritten = file_put_contents($outputFile, $combined);

    if ($bytesWritten === false) {
        return [
            'success' => false,
            'error' => 'Failed to write output file: ' . $outputFile
        ];
    }

    // Check bundle size
    if ($bytesWritten > $maxBundleSize) {
        $logger->LogError("CSS bundle exceeds size limit: " . formatBytes($bytesWritten) . " > " . formatBytes($maxBundleSize));
        return [
            'success' => false,
            'error' => "Bundle size exceeds limit! " . formatBytes($bytesWritten) . " > " . formatBytes($maxBundleSize) . " (50KB)"
        ];
    }

    // Generate and write version hash
    $hash = substr(md5_file($outputFile), 0, 8);
    file_put_contents($versionFile, $hash);

    $buildTime = round((microtime(true) - $startTime) * 1000);

    echo "\n📊 Build Summary:\n";
    echo "   Output: " . str_replace(dirname(dirname($adminCssDir)) . '/', '', $outputFile) . "\n";
    echo "   Size: " . formatBytes($bytesWritten) . " / " . formatBytes($maxBundleSize) . " (" . round(($bytesWritten / $maxBundleSize) * 100) . "% of limit)\n";
    echo "   Version hash: $hash\n";
    echo "   Build time: {$buildTime}ms\n";

    if ($minify) {
        echo "   Mode: Production (minified)\n";
    } else {
        echo "   Mode: Development\n";
    }

    $logger->LogInfo("CSS build complete: " . formatBytes($bytesWritten) . ", hash: $hash");

    return [
        'success' => true,
        'size' => $bytesWritten,
        'hash' => $hash
    ];
}

/**
 * Simple CSS minification (no external dependencies)
 * Removes comments, extra whitespace, and newlines
 */
function minifyCss($css) {
    // Remove comments
    $css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css);

    // Remove multiple spaces
    $css = preg_replace('/\s+/', ' ', $css);

    // Remove spaces around special characters
    $css = preg_replace('/\s*([{};:,>~+])\s*/', '$1', $css);

    // Remove trailing semicolons before closing braces
    $css = str_replace(';}', '}', $css);

    // Remove newlines and leading/trailing whitespace
    $css = trim($css);

    return $css;
}

/**
 * Format bytes to human-readable string
 */
function formatBytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB'];

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= pow(1024, $pow);

    return round($bytes, $precision) . ' ' . $units[$pow];
}

/**
 * Delete Customer Data - Privacy Compliance Command
 *
 * Scans all store databases for customer records matching a phone number
 * and anonymizes (soft-deletes) the personal information.
 *
 * Usage:
 *   php conductor.php delete-customer-data <phone_number>
 *   php conductor.php delete-customer-data <phone_number> --dry-run
 *
 * @param array $argv Command line arguments
 */
function deleteCustomerData($argv) {
    global $logger;

    // Parse arguments
    $phone = $argv[2] ?? null;
    $dryRun = in_array('--dry-run', $argv);
    $requestId = null;

    // Check for --request-id flag
    foreach ($argv as $arg) {
        if (strpos($arg, '--request-id=') === 0) {
            $requestId = substr($arg, 13);
        }
    }

    if (!$phone) {
        echo "Usage: php conductor.php delete-customer-data <phone_number> [--dry-run] [--request-id=UUID]\n";
        echo "Example: php conductor.php delete-customer-data 5551234567\n";
        echo "Example: php conductor.php delete-customer-data 5551234567 --dry-run\n";
        echo "\nOptions:\n";
        echo "  --dry-run       Show what would be deleted without making changes\n";
        echo "  --request-id    Link to a deletion request record for tracking\n";
        exit(1);
    }

    // Normalize phone number (remove non-digits)
    $normalizedPhone = preg_replace('/[^0-9]/', '', $phone);

    if (strlen($normalizedPhone) < 10) {
        echo "Error: Please provide a valid phone number with at least 10 digits.\n";
        exit(1);
    }

    echo "╔══════════════════════════════════════════════════════════════╗\n";
    echo "║           CUSTOMER DATA DELETION - PRIVACY COMPLIANCE       ║\n";
    echo "╚══════════════════════════════════════════════════════════════╝\n\n";

    if ($dryRun) {
        echo "🔍 DRY RUN MODE - No changes will be made\n\n";
    }

    echo "Phone number: {$normalizedPhone}\n";
    if ($requestId) {
        echo "Request ID: {$requestId}\n";
    }
    echo str_repeat("-", 60) . "\n\n";

    $logger->LogInfo("Starting customer data deletion for phone: {$normalizedPhone}" . ($dryRun ? " (DRY RUN)" : ""));

    try {
        // Get all active stores
        $stores = getAllStoresData(1, 1); // Include dev stores to be thorough
        $totalStores = count($stores);
        $storesProcessed = 0;
        $totalRecordsFound = 0;
        $totalRecordsDeleted = 0;
        $storeResults = [];

        echo "Scanning {$totalStores} store databases...\n\n";

        foreach ($stores as $store) {
            $typeNum = $store->getTypeNum();
            $dbName = $store->getDbName();
            $storesProcessed++;

            try {
                $storeDb = dbConnectByName($dbName);

                if (!$storeDb) {
                    echo "  ⚠️  {$typeNum}: Could not connect to database\n";
                    continue;
                }

                // Search for customers with matching phone
                // Handle various phone formats: exact match, with/without country code
                $phoneVariants = [
                    $normalizedPhone,
                    '1' . $normalizedPhone, // US country code
                    substr($normalizedPhone, -10), // Last 10 digits
                ];

                $placeholders = implode(',', array_fill(0, count($phoneVariants), '?'));
                $searchQuery = "SELECT customerID, firstName, lastName, phone, email FROM customers WHERE phone IN ({$placeholders}) OR REPLACE(REPLACE(REPLACE(REPLACE(phone, '-', ''), '(', ''), ')', ''), ' ', '') IN ({$placeholders})";

                $stmt = $storeDb->prepare($searchQuery);
                $params = array_merge($phoneVariants, $phoneVariants);
                $stmt->execute($params);

                $customers = $stmt->fetchAll(PDO::FETCH_ASSOC);

                if (count($customers) > 0) {
                    $totalRecordsFound += count($customers);

                    foreach ($customers as $customer) {
                        $custId = $customer['customerID'];
                        $custName = "{$customer['firstName']} {$customer['lastName']}";

                        echo "  📍 {$typeNum}: Found customer #{$custId} - {$custName}\n";

                        if (!$dryRun) {
                            // Anonymize customer record
                            $updateStmt = $storeDb->prepare("
                                UPDATE customers SET
                                    firstName = 'DELETED',
                                    lastName = 'DELETED',
                                    email = 'deleted@deleted.com',
                                    phone = CONCAT('DELETED-', customerID),
                                    address = 'DELETED',
                                    city = 'DELETED',
                                    state = 'XX',
                                    zipcode = '00000',
                                    driversLicense = 'DELETED',
                                    onSMS = 0,
                                    onEmail = 0,
                                    addedToSMS = 0,
                                    addedToEmail = 0
                                WHERE customerID = ?
                            ");
                            $updateStmt->execute([$custId]);

                            // Also anonymize in customerAlerts if exists
                            try {
                                $alertStmt = $storeDb->prepare("
                                    UPDATE customerAlerts SET
                                        notes = 'DELETED - Privacy Request'
                                    WHERE customerID = ?
                                ");
                                $alertStmt->execute([$custId]);
                            } catch (PDOException $e) {
                                // Table might not exist in all stores
                            }

                            $totalRecordsDeleted++;
                            echo "     ✅ Anonymized\n";
                            $logger->LogInfo("Anonymized customer #{$custId} in {$typeNum}");
                        } else {
                            echo "     🔸 Would be anonymized\n";
                        }
                    }

                    $storeResults[$typeNum] = count($customers);
                }

            } catch (PDOException $e) {
                echo "  ⚠️  {$typeNum}: Database error - " . $e->getMessage() . "\n";
                $logger->LogError("Error scanning {$typeNum}: " . $e->getMessage());
            }

            // Progress indicator
            if ($storesProcessed % 10 === 0) {
                echo "  ... processed {$storesProcessed}/{$totalStores} stores\n";
            }
        }

        // Update deletion request record if linked
        if ($requestId && !$dryRun) {
            try {
                $centralDb = dbConnectByName('kiosk_buykiosk');
                $updateRequestStmt = $centralDb->prepare("
                    UPDATE dataDeletionRequests SET
                        status = 'completed',
                        storesProcessed = ?,
                        recordsDeleted = ?,
                        processedAt = NOW(),
                        notes = ?
                    WHERE requestId = ?
                ");
                $notes = "Processed {$storesProcessed} stores, found {$totalRecordsFound} records, anonymized {$totalRecordsDeleted}";
                $updateRequestStmt->execute([$storesProcessed, $totalRecordsDeleted, $notes, $requestId]);
                echo "\n✅ Updated deletion request record\n";
            } catch (PDOException $e) {
                echo "\n⚠️  Could not update deletion request record: " . $e->getMessage() . "\n";
            }
        }

        // Summary
        echo "\n" . str_repeat("=", 60) . "\n";
        echo "SUMMARY\n";
        echo str_repeat("=", 60) . "\n";
        echo "Stores scanned: {$storesProcessed}\n";
        echo "Records found: {$totalRecordsFound}\n";

        if ($dryRun) {
            echo "Records that would be anonymized: {$totalRecordsFound}\n";
            echo "\n⚠️  This was a DRY RUN. Run without --dry-run to apply changes.\n";
        } else {
            echo "Records anonymized: {$totalRecordsDeleted}\n";
            echo "\n✅ Deletion complete.\n";
        }

        if (count($storeResults) > 0) {
            echo "\nStores with matches:\n";
            foreach ($storeResults as $store => $count) {
                echo "  - {$store}: {$count} record(s)\n";
            }
        }

        $logger->LogInfo("Customer data deletion completed: {$totalRecordsDeleted} records anonymized across {$storesProcessed} stores");

    } catch (Exception $e) {
        echo "\nFATAL ERROR: " . $e->getMessage() . "\n";
        $logger->LogError("Fatal error in customer data deletion: " . $e->getMessage());
        exit(1);
    }
}

/**
 * List pending data deletion requests
 *
 * Usage:
 *   php conductor.php list-deletion-requests
 *   php conductor.php list-deletion-requests --status=pending
 *
 * @param array $argv Command line arguments
 */
function listDeletionRequests($argv) {
    global $logger;

    // Parse status filter
    $statusFilter = 'pending';
    foreach ($argv as $arg) {
        if (strpos($arg, '--status=') === 0) {
            $statusFilter = substr($arg, 9);
        }
    }

    // Validate status
    $validStatuses = ['pending', 'processing', 'completed', 'failed', 'rejected', 'all'];
    if (!in_array($statusFilter, $validStatuses)) {
        echo "Invalid status. Valid options: " . implode(', ', $validStatuses) . "\n";
        exit(1);
    }

    try {
        $db = dbConnectByName('kiosk_buykiosk');

        // Check if table exists
        $tableCheck = $db->query("SHOW TABLES LIKE 'dataDeletionRequests'");
        if ($tableCheck->rowCount() === 0) {
            echo "Data deletion requests table not found. Run migrations first:\n";
            echo "  php conductor.php run\n";
            exit(1);
        }

        $query = "SELECT * FROM dataDeletionRequests";
        if ($statusFilter !== 'all') {
            $query .= " WHERE status = ?";
        }
        $query .= " ORDER BY createdAt DESC LIMIT 50";

        $stmt = $db->prepare($query);
        if ($statusFilter !== 'all') {
            $stmt->execute([$statusFilter]);
        } else {
            $stmt->execute();
        }

        $requests = $stmt->fetchAll(PDO::FETCH_ASSOC);

        echo "╔══════════════════════════════════════════════════════════════╗\n";
        echo "║              DATA DELETION REQUESTS                         ║\n";
        echo "╚══════════════════════════════════════════════════════════════╝\n\n";

        echo "Status filter: {$statusFilter}\n";
        echo "Total results: " . count($requests) . "\n\n";

        if (count($requests) === 0) {
            echo "No requests found.\n";
            return;
        }

        echo str_repeat("-", 100) . "\n";
        printf("%-36s | %-15s | %-10s | %-20s | %s\n", "Request ID", "Phone", "Status", "Created", "Name");
        echo str_repeat("-", 100) . "\n";

        foreach ($requests as $request) {
            $name = trim(($request['firstName'] ?? '') . ' ' . ($request['lastName'] ?? ''));
            $name = $name ?: 'N/A';

            printf(
                "%-36s | %-15s | %-10s | %-20s | %s\n",
                $request['requestId'],
                $request['phone'],
                $request['status'],
                $request['createdAt'],
                substr($name, 0, 30)
            );
        }

        echo str_repeat("-", 100) . "\n";

        echo "\nTo process a request, run:\n";
        echo "  php conductor.php delete-customer-data <phone> --request-id=<requestId>\n";

    } catch (PDOException $e) {
        echo "Database error: " . $e->getMessage() . "\n";
        $logger->LogError("Error listing deletion requests: " . $e->getMessage());
        exit(1);
    }
}

/**
 * Migrate a store from one store number to another
 *
 * Usage:
 *   php conductor.php migrate-store <old_typeNum> <new_typeNum>             (dry run)
 *   php conductor.php migrate-store <old_typeNum> <new_typeNum> --execute   (execute)
 *
 * @param array $argv Command line arguments
 */
function migrateStoreNumber($argv) {
    $oldTypeNum = $argv[2] ?? null;
    $newTypeNum = $argv[3] ?? null;
    $execute = in_array('--execute', $argv);

    if (!$oldTypeNum || !$newTypeNum) {
        echo "Usage: php conductor.php migrate-store <old_typeNum> <new_typeNum> [--execute]\n";
        echo "Example: php conductor.php migrate-store pc80469 pc80996            (dry run)\n";
        echo "Example: php conductor.php migrate-store pc80469 pc80996 --execute  (execute)\n";
        exit(1);
    }

    require_once __DIR__ . '/services/StoreMigrationService.php';

    $service = new \UserFrosting\Services\StoreMigrationService();
    $success = $service->migrateStore($oldTypeNum, $newTypeNum, $execute);

    exit($success ? 0 : 1);
}

/**
 * Copy sales and buys data from one store to another in kiosk_sales.
 *
 * Copies records from the source store's typeNum to the destination store's typeNum.
 * Uses incremental sync: only copies records newer than the latest date already
 * present in the destination. Safe to run multiple times without producing duplicates
 * (uses INSERT ... ON DUPLICATE KEY UPDATE on the code+typeNum unique constraint).
 *
 * Usage:
 *   php conductor.php copy-sales <source_typeNum> <dest_typeNum>
 *   php conductor.php copy-sales pc80586 pc00
 *
 * @param array $argv Command line arguments
 */
function copySalesData($argv) {
    global $logger;

    $sourceTypeNum = $argv[2] ?? null;
    $destTypeNum = $argv[3] ?? null;

    if (!$sourceTypeNum || !$destTypeNum) {
        echo "Usage: php conductor.php copy-sales <source_typeNum> <dest_typeNum>\n";
        echo "Example: php conductor.php copy-sales pc80586 pc00\n";
        echo "\nCopies buys and sales records from kiosk_sales for the source store\n";
        echo "to the destination store. Incremental — only copies new records on re-run.\n";
        exit(1);
    }

    if ($sourceTypeNum === $destTypeNum) {
        echo "Error: Source and destination cannot be the same store.\n";
        exit(1);
    }

    echo "Copying sales data from $sourceTypeNum to $destTypeNum...\n";
    $logger->LogInfo("copy-sales: Starting copy from $sourceTypeNum to $destTypeNum");

    try {
        $db = dbConnectByName('kiosk_sales');

        // --- BUYS TABLE ---
        echo "\n--- buys table ---\n";

        // Find the latest buyDate in the destination to enable incremental copy
        $stmt = $db->prepare("SELECT MAX(buyDate) as latestDate, COUNT(*) as cnt FROM buys WHERE typeNum = :typeNum");
        $stmt->execute(['typeNum' => $destTypeNum]);
        $destInfo = $stmt->fetch(PDO::FETCH_ASSOC);

        $destBuysCount = (int)$destInfo['cnt'];
        $destLatestBuyDate = $destInfo['latestDate'];

        // Count source records for progress display
        $stmt = $db->prepare("SELECT COUNT(*) as cnt FROM buys WHERE typeNum = :typeNum");
        $stmt->execute(['typeNum' => $sourceTypeNum]);
        $sourceBuysCount = (int)$stmt->fetch(PDO::FETCH_ASSOC)['cnt'];

        echo "Source ($sourceTypeNum): $sourceBuysCount buys records\n";
        echo "Destination ($destTypeNum): $destBuysCount existing buys records\n";

        if ($sourceBuysCount === 0) {
            echo "No buys records found in source store. Skipping.\n";
        } else {
            // Fetch source records — incremental if dest already has data
            if ($destLatestBuyDate) {
                echo "Incremental mode: copying buys with buyDate > $destLatestBuyDate\n";
                $stmt = $db->prepare("
                    SELECT code, buyDate, description, quantity, price, cost,
                           deptID, catID, subCatID, sizeID, brandID
                    FROM buys
                    WHERE typeNum = :typeNum AND buyDate > :sinceDate
                    ORDER BY buyDate ASC
                ");
                $stmt->execute(['typeNum' => $sourceTypeNum, 'sinceDate' => $destLatestBuyDate]);
            } else {
                echo "Initial copy: copying all buys records\n";
                $stmt = $db->prepare("
                    SELECT code, buyDate, description, quantity, price, cost,
                           deptID, catID, subCatID, sizeID, brandID
                    FROM buys
                    WHERE typeNum = :typeNum
                    ORDER BY buyDate ASC
                ");
                $stmt->execute(['typeNum' => $sourceTypeNum]);
            }

            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            echo "Records to copy: " . count($rows) . "\n";

            if (count($rows) > 0) {
                $insertStmt = $db->prepare("
                    INSERT INTO buys (code, buyDate, description, quantity, price, cost,
                                      deptID, catID, subCatID, sizeID, brandID, typeNum)
                    VALUES (:code, :buyDate, :description, :quantity, :price, :cost,
                            :deptID, :catID, :subCatID, :sizeID, :brandID, :typeNum)
                    ON DUPLICATE KEY UPDATE
                        buyDate = VALUES(buyDate),
                        description = VALUES(description),
                        quantity = VALUES(quantity),
                        price = VALUES(price),
                        cost = VALUES(cost),
                        deptID = VALUES(deptID),
                        catID = VALUES(catID),
                        subCatID = VALUES(subCatID),
                        sizeID = VALUES(sizeID),
                        brandID = VALUES(brandID)
                ");

                $copied = 0;
                foreach ($rows as $row) {
                    $row['typeNum'] = $destTypeNum;
                    $insertStmt->execute($row);
                    $copied++;
                    if ($copied % 1000 === 0) {
                        echo "  Progress: $copied / " . count($rows) . " buys\n";
                    }
                }
                echo "Copied $copied buys records.\n";
            }
        }

        // --- SALES TABLE ---
        echo "\n--- sales table ---\n";

        // Find the latest salesDate in the destination
        $stmt = $db->prepare("SELECT MAX(salesDate) as latestDate, COUNT(*) as cnt FROM sales WHERE typeNum = :typeNum");
        $stmt->execute(['typeNum' => $destTypeNum]);
        $destInfo = $stmt->fetch(PDO::FETCH_ASSOC);

        $destSalesCount = (int)$destInfo['cnt'];
        $destLatestSalesDate = $destInfo['latestDate'];

        // Count source
        $stmt = $db->prepare("SELECT COUNT(*) as cnt FROM sales WHERE typeNum = :typeNum");
        $stmt->execute(['typeNum' => $sourceTypeNum]);
        $sourceSalesCount = (int)$stmt->fetch(PDO::FETCH_ASSOC)['cnt'];

        echo "Source ($sourceTypeNum): $sourceSalesCount sales records\n";
        echo "Destination ($destTypeNum): $destSalesCount existing sales records\n";

        if ($sourceSalesCount === 0) {
            echo "No sales records found in source store. Skipping.\n";
        } else {
            if ($destLatestSalesDate) {
                echo "Incremental mode: copying sales with salesDate > $destLatestSalesDate\n";
                $stmt = $db->prepare("
                    SELECT code, buyDate, salesDate, description, quantity, price, cost,
                           deptID, catID, subCatID, sizeID, brandID
                    FROM sales
                    WHERE typeNum = :typeNum AND salesDate > :sinceDate
                    ORDER BY salesDate ASC
                ");
                $stmt->execute(['typeNum' => $sourceTypeNum, 'sinceDate' => $destLatestSalesDate]);
            } else {
                echo "Initial copy: copying all sales records\n";
                $stmt = $db->prepare("
                    SELECT code, buyDate, salesDate, description, quantity, price, cost,
                           deptID, catID, subCatID, sizeID, brandID
                    FROM sales
                    WHERE typeNum = :typeNum
                    ORDER BY salesDate ASC
                ");
                $stmt->execute(['typeNum' => $sourceTypeNum]);
            }

            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            echo "Records to copy: " . count($rows) . "\n";

            if (count($rows) > 0) {
                $insertStmt = $db->prepare("
                    INSERT INTO sales (code, buyDate, salesDate, description, quantity, price, cost,
                                       deptID, catID, subCatID, sizeID, brandID, typeNum)
                    VALUES (:code, :buyDate, :salesDate, :description, :quantity, :price, :cost,
                            :deptID, :catID, :subCatID, :sizeID, :brandID, :typeNum)
                    ON DUPLICATE KEY UPDATE
                        buyDate = VALUES(buyDate),
                        salesDate = VALUES(salesDate),
                        description = VALUES(description),
                        quantity = VALUES(quantity),
                        price = VALUES(price),
                        cost = VALUES(cost),
                        deptID = VALUES(deptID),
                        catID = VALUES(catID),
                        subCatID = VALUES(subCatID),
                        sizeID = VALUES(sizeID),
                        brandID = VALUES(brandID)
                ");

                $copied = 0;
                foreach ($rows as $row) {
                    $row['typeNum'] = $destTypeNum;
                    $insertStmt->execute($row);
                    $copied++;
                    if ($copied % 1000 === 0) {
                        echo "  Progress: $copied / " . count($rows) . " sales\n";
                    }
                }
                echo "Copied $copied sales records.\n";
            }
        }

        // --- STORE METRICS DAILY (peer analysis) ---
        echo "\n--- storeMetricsDaily (peer analysis) ---\n";

        $centralDb = dbConnectByName('kiosk_buykiosk');

        // Find latest date in destination
        $stmt = $centralDb->prepare("SELECT MAX(date) as latestDate, COUNT(*) as cnt FROM storeMetricsDaily WHERE typeNum = :typeNum");
        $stmt->execute(['typeNum' => $destTypeNum]);
        $destInfo = $stmt->fetch(PDO::FETCH_ASSOC);
        $destMetricsCount = (int)$destInfo['cnt'];
        $destLatestMetricsDate = $destInfo['latestDate'];

        $stmt = $centralDb->prepare("SELECT COUNT(*) as cnt FROM storeMetricsDaily WHERE typeNum = :typeNum");
        $stmt->execute(['typeNum' => $sourceTypeNum]);
        $sourceMetricsCount = (int)$stmt->fetch(PDO::FETCH_ASSOC)['cnt'];

        echo "Source ($sourceTypeNum): $sourceMetricsCount metric rows\n";
        echo "Destination ($destTypeNum): $destMetricsCount existing metric rows\n";

        if ($sourceMetricsCount === 0) {
            echo "No metrics found in source store. Skipping.\n";
        } else {
            if ($destLatestMetricsDate) {
                echo "Incremental mode: copying metrics with date > $destLatestMetricsDate\n";
                $stmt = $centralDb->prepare("
                    SELECT date, storeType, buyCount, avgWaitMinutes, medianWaitMinutes, maxWaitMinutes,
                           totalRevenue, avgPurchaseAmount, uniqueCustomers, repeatCustomers, npsScore, npsResponses
                    FROM storeMetricsDaily
                    WHERE typeNum = :typeNum AND date > :sinceDate
                    ORDER BY date ASC
                ");
                $stmt->execute(['typeNum' => $sourceTypeNum, 'sinceDate' => $destLatestMetricsDate]);
            } else {
                echo "Initial copy: copying all metrics\n";
                $stmt = $centralDb->prepare("
                    SELECT date, storeType, buyCount, avgWaitMinutes, medianWaitMinutes, maxWaitMinutes,
                           totalRevenue, avgPurchaseAmount, uniqueCustomers, repeatCustomers, npsScore, npsResponses
                    FROM storeMetricsDaily
                    WHERE typeNum = :typeNum
                    ORDER BY date ASC
                ");
                $stmt->execute(['typeNum' => $sourceTypeNum]);
            }

            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            echo "Records to copy: " . count($rows) . "\n";

            if (count($rows) > 0) {
                $insertStmt = $centralDb->prepare("
                    INSERT INTO storeMetricsDaily (typeNum, date, storeType, buyCount, avgWaitMinutes, medianWaitMinutes,
                                                   maxWaitMinutes, totalRevenue, avgPurchaseAmount, uniqueCustomers,
                                                   repeatCustomers, npsScore, npsResponses)
                    VALUES (:typeNum, :date, :storeType, :buyCount, :avgWaitMinutes, :medianWaitMinutes,
                            :maxWaitMinutes, :totalRevenue, :avgPurchaseAmount, :uniqueCustomers,
                            :repeatCustomers, :npsScore, :npsResponses)
                    ON DUPLICATE KEY UPDATE
                        storeType = VALUES(storeType),
                        buyCount = VALUES(buyCount),
                        avgWaitMinutes = VALUES(avgWaitMinutes),
                        medianWaitMinutes = VALUES(medianWaitMinutes),
                        maxWaitMinutes = VALUES(maxWaitMinutes),
                        totalRevenue = VALUES(totalRevenue),
                        avgPurchaseAmount = VALUES(avgPurchaseAmount),
                        uniqueCustomers = VALUES(uniqueCustomers),
                        repeatCustomers = VALUES(repeatCustomers),
                        npsScore = VALUES(npsScore),
                        npsResponses = VALUES(npsResponses)
                ");

                $copied = 0;
                foreach ($rows as $row) {
                    $row['typeNum'] = $destTypeNum;
                    $insertStmt->execute($row);
                    $copied++;
                }
                echo "Copied $copied metric rows.\n";
            }
        }

        echo "\nDone! Sales data copy from $sourceTypeNum to $destTypeNum complete.\n";
        $logger->LogInfo("copy-sales: Completed copy from $sourceTypeNum to $destTypeNum");

    } catch (Exception $e) {
        echo "Error: " . $e->getMessage() . "\n";
        $logger->LogError("copy-sales failed: " . $e->getMessage());
        exit(1);
    }
}

