<?php
/**
 * BUG SCANNER - Comprehensive System Health Check
 * Scans all functions, buttons, API endpoints, and reports potential bugs
 */

session_name('FONFIX_SYSTEM_ID');
session_start();
require 'db.php';

// Only allow master/admin access
$user_role = $_SESSION['role'] ?? '';
$username = strtolower($_SESSION['user'] ?? '');
$is_admin = ($user_role === 'master' || $username === 'endie');

if (!$is_admin) {
    die("Access Denied. Master/Admin only.");
}

header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html>
<head>
    <title>Bug Scanner - System Health Check</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
        .container { max-width: 1400px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        h1 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 10px; }
        h2 { color: #34495e; margin-top: 30px; border-left: 4px solid #3498db; padding-left: 10px; }
        .section { margin: 20px 0; padding: 15px; background: #f8f9fa; border-radius: 5px; }
        .error { background: #fee; border-left: 4px solid #e74c3c; padding: 10px; margin: 5px 0; }
        .warning { background: #fff3cd; border-left: 4px solid #ffc107; padding: 10px; margin: 5px 0; }
        .success { background: #d4edda; border-left: 4px solid #28a745; padding: 10px; margin: 5px 0; }
        .info { background: #d1ecf1; border-left: 4px solid #17a2b8; padding: 10px; margin: 5px 0; }
        .code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-family: monospace; font-size: 0.9em; }
        table { width: 100%; border-collapse: collapse; margin: 10px 0; }
        th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background: #3498db; color: white; }
        tr:hover { background: #f5f5f5; }
        .badge { display: inline-block; padding: 3px 8px; border-radius: 3px; font-size: 0.85em; font-weight: bold; }
        .badge-error { background: #e74c3c; color: white; }
        .badge-warning { background: #f39c12; color: white; }
        .badge-success { background: #27ae60; color: white; }
        .stats { display: flex; gap: 20px; margin: 20px 0; }
        .stat-box { flex: 1; padding: 15px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 8px; text-align: center; }
        .stat-box h3 { margin: 0; font-size: 2em; }
        .stat-box p { margin: 5px 0 0 0; opacity: 0.9; }
        button { background: #3498db; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; margin: 5px; }
        button:hover { background: #2980b9; }
        .timestamp { color: #7f8c8d; font-size: 0.9em; }
    </style>
</head>
<body>
<div class="container">
    <h1>🔍 BUG SCANNER - System Health Check</h1>
    <p class="timestamp">Scan Date: <?php echo date('Y-m-d H:i:s'); ?></p>
    
    <?php
    $errors = [];
    $warnings = [];
    $info = [];
    $stats = [
        'functions' => 0,
        'buttons' => 0,
        'api_endpoints' => 0,
        'issues_found' => 0
    ];

    // ============================================
    // 1. SCAN JAVASCRIPT FUNCTIONS
    // ============================================
    echo "<h2>1. JavaScript Functions Analysis</h2>";
    $dashboardContent = file_get_contents('dashboard.php');
    
    // Extract all function declarations
    preg_match_all('/function\s+(\w+)\s*\(/i', $dashboardContent, $functionMatches);
    $declaredFunctions = $functionMatches[1] ?? [];
    $stats['functions'] = count($declaredFunctions);
    
    echo "<div class='section'>";
    echo "<p><strong>Total Functions Found:</strong> " . count($declaredFunctions) . "</p>";
    
    // Check for duplicate function names
    $duplicates = array_diff_assoc($declaredFunctions, array_unique($declaredFunctions));
    if (!empty($duplicates)) {
        $errors[] = "Duplicate function declarations found: " . implode(', ', array_unique($duplicates));
        echo "<div class='error'>⚠️ <strong>DUPLICATE FUNCTIONS:</strong> " . implode(', ', array_unique($duplicates)) . "</div>";
    }
    
    // Check for functions that might be missing
    preg_match_all('/onclick=["\']([^"\']+)["\']/i', $dashboardContent, $onclickMatches);
    $onclickHandlers = $onclickMatches[1] ?? [];
    $stats['buttons'] = count($onclickHandlers);
    
    echo "<p><strong>Total onclick Handlers:</strong> " . count($onclickHandlers) . "</p>";
    
    // Extract function calls from onclick handlers
    $calledFunctions = [];
    $builtInFunctions = ['alert', 'confirm', 'prompt', 'console', 'window', 'document', 'parseInt', 'parseFloat', 'isNaN', 'encodeURIComponent', 'decodeURIComponent', 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'JSON', 'Array', 'Object', 'String', 'Number', 'Date', 'Math', 'RegExp'];
    
    foreach ($onclickHandlers as $handler) {
        // Remove quotes, extract function name
        $handler = trim($handler, "'\"");
        // Match function calls (e.g., "functionName()" or "functionName(param)")
        if (preg_match('/^(\w+)\s*\(/', $handler, $match)) {
            $funcName = $match[1];
            // Skip built-in browser functions
            if (!in_array(strtolower($funcName), array_map('strtolower', $builtInFunctions))) {
                $calledFunctions[] = $funcName;
            }
        }
    }
    
    // Check if called functions exist
    $missingFunctions = array_diff(array_unique($calledFunctions), $declaredFunctions);
    if (!empty($missingFunctions)) {
        $errors[] = "Functions called but not defined: " . implode(', ', $missingFunctions);
        echo "<div class='error'>❌ <strong>MISSING FUNCTIONS:</strong><ul>";
        foreach ($missingFunctions as $func) {
            echo "<li><code class='code'>$func()</code> is called but not defined</li>";
        }
        echo "</ul></div>";
    } else {
        echo "<div class='success'>✅ All onclick handler functions are defined</div>";
    }
    
    // Check for common JavaScript errors
    if (preg_match('/const\s+(\w+).*const\s+\1/i', $dashboardContent)) {
        $errors[] = "Potential redeclaration of const variables detected";
        echo "<div class='error'>⚠️ Potential const redeclaration detected</div>";
    }
    
    // Check for unreachable code after return (but ignore valid patterns like return showToast() or return; })
    // Only flag if there's actual code after return that's not a function call or closing brace
    $unreachablePattern = '/return\s+(?:showToast|alert|console\.(?:log|error|warn)|[^;()]+\([^)]*\));\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[=;]/i';
    $unreachableMatches = preg_match_all($unreachablePattern, $dashboardContent, $unreachableCode);
    if ($unreachableMatches > 0) {
        $warnings[] = "Potential unreachable code after return statements: $unreachableMatches instance(s)";
        echo "<div class='warning'>⚠️ <strong>Potential unreachable code after return:</strong> $unreachableMatches instance(s) found. Review code after return statements.</div>";
    } else {
        echo "<div class='success'>✅ No obvious unreachable code after return statements</div>";
    }
    
    echo "</div>";

    // ============================================
    // 2. SCAN API ENDPOINTS
    // ============================================
    echo "<h2>2. API Endpoints Analysis</h2>";
    $apiContent = file_get_contents('api.php');
    
    // Extract all API actions - only from actual if conditions checking $action
    // Pattern: if ($action === 'action_name') or if ($action == 'action_name')
    // Must be checking $action variable, not other variables
    preg_match_all('/if\s*\([^)]*\$action\s*[=!]+\s*["\']([^"\']+)["\']/i', $apiContent, $actionMatches);
    $apiActions = $actionMatches[1] ?? [];
    
    // Also extract from combined conditions (e.g., "action === 'fetch_jobs' || action === 'fetch_retail_history'")
    // Only match if it's part of an if condition with $action
    preg_match_all('/if\s*\([^)]*\$action\s*[=!]+\s*["\']([^"\']+)["\']\s*\|\|\s*\$action\s*[=!]+\s*["\']([^"\']+)["\']/i', $apiContent, $combinedMatches);
    if (!empty($combinedMatches[1])) {
        $apiActions = array_merge($apiActions, $combinedMatches[1], $combinedMatches[2]);
    }
    
    // Filter out false positives:
    // - 'RESTORE' is a constant, not an API action
    // - 'master' is a role check, not an API action  
    // - Single uppercase words are likely constants
    // - Only keep actions that look like valid API endpoint names (lowercase with underscores)
    $validActions = [];
    $falsePositives = ['RESTORE', 'master', 'Refund', 'Gombak', 'Completed', 'stock_gombak', 'stock_sr', 'cost'];
    
    foreach ($apiActions as $action) {
        $action = trim($action);
        // Skip known false positives
        if (in_array($action, $falsePositives)) continue;
        // Valid API actions are typically lowercase with underscores
        // Filter out single uppercase words (constants) and role checks
        if (preg_match('/^[a-z][a-z0-9_]*$/', $action) && strlen($action) > 2) {
            $validActions[] = $action;
        }
    }
    $apiActions = array_unique($validActions);
    $stats['api_endpoints'] = count($apiActions);
    
    echo "<div class='section'>";
    echo "<p><strong>Total API Endpoints Found:</strong> " . count($apiActions) . "</p>";
    
    // Check for duplicate actions (shouldn't happen after array_unique, but check anyway)
    $duplicateActions = [];
    $seen = [];
    foreach ($apiActions as $action) {
        if (isset($seen[$action])) {
            $duplicateActions[] = $action;
        }
        $seen[$action] = true;
    }
    if (!empty($duplicateActions)) {
        $errors[] = "Duplicate API actions found: " . implode(', ', array_unique($duplicateActions));
        echo "<div class='error'>⚠️ <strong>DUPLICATE API ACTIONS:</strong> " . implode(', ', array_unique($duplicateActions)) . "</div>";
    } else {
        echo "<div class='success'>✅ No duplicate API actions found</div>";
    }
    
    // Find API calls in dashboard
    preg_match_all('/api\.php\?action=([^&"\']+)/i', $dashboardContent, $apiCalls);
    $calledActions = $apiCalls[1] ?? [];
    
    // Check if called API actions exist
    $missingActions = array_diff(array_unique($calledActions), $apiActions);
    if (!empty($missingActions)) {
        $errors[] = "API actions called but not defined: " . implode(', ', $missingActions);
        echo "<div class='error'>❌ <strong>MISSING API ACTIONS:</strong><ul>";
        foreach ($missingActions as $action) {
            echo "<li><code class='code'>$action</code> is called but not defined in api.php</li>";
        }
        echo "</ul></div>";
    } else {
        echo "<div class='success'>✅ All API actions are properly defined</div>";
    }
    
    // List all API endpoints
    echo "<div class='info'><strong>All API Endpoints:</strong><ul style='columns: 3;'>";
    foreach (array_unique($apiActions) as $action) {
        echo "<li><code class='code'>$action</code></li>";
    }
    echo "</ul></div>";
    
    echo "</div>";

    // ============================================
    // 3. DATABASE CONNECTION CHECK
    // ============================================
    echo "<h2>3. Database Health Check</h2>";
    echo "<div class='section'>";
    
    try {
        // Check connection
        $pdo->query("SELECT 1");
        echo "<div class='success'>✅ Database connection successful</div>";
        
        // Check required tables
        $requiredTables = ['jobs', 'stock_list', 'users', 'activity_logs', 'credit_notes', 'expenses'];
        $existingTables = [];
        $stmt = $pdo->query("SHOW TABLES");
        while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
            $existingTables[] = $row[0];
        }
        
        $missingTables = array_diff($requiredTables, $existingTables);
        if (!empty($missingTables)) {
            $errors[] = "Missing database tables: " . implode(', ', $missingTables);
            echo "<div class='error'>❌ <strong>MISSING TABLES:</strong> " . implode(', ', $missingTables) . "</div>";
        } else {
            echo "<div class='success'>✅ All required tables exist</div>";
        }
        
        // Check for foreign key constraints
        $fkCheck = $pdo->query("SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL");
        $fkCount = $fkCheck->fetchColumn();
        echo "<div class='info'>ℹ️ Foreign key constraints: $fkCount</div>";
        
    } catch (Exception $e) {
        $errors[] = "Database error: " . $e->getMessage();
        echo "<div class='error'>❌ Database error: " . htmlspecialchars($e->getMessage()) . "</div>";
    }
    
    echo "</div>";

    // ============================================
    // 4. FORM VALIDATION CHECK
    // ============================================
    echo "<h2>4. Form & Input Validation</h2>";
    echo "<div class='section'>";
    
    // Check for required fields without validation
    preg_match_all('/<input[^>]*required[^>]*>/i', $dashboardContent, $requiredInputs);
    echo "<div class='info'>ℹ️ Required input fields: " . count($requiredInputs[0]) . "</div>";
    
    // Check for form submissions without CSRF protection
    preg_match_all('/fetch\([^)]*api\.php/i', $dashboardContent, $fetchCalls);
    $csrfChecks = preg_match_all('/CSRF|csrf_token|X-CSRF-Token/i', $dashboardContent);
    
    if ($csrfChecks < count($fetchCalls[0]) / 2) {
        $warnings[] = "Some API calls may be missing CSRF protection";
        echo "<div class='warning'>⚠️ Some API calls may be missing CSRF token protection</div>";
    } else {
        echo "<div class='success'>✅ CSRF protection appears to be implemented</div>";
    }
    
    echo "</div>";

    // ============================================
    // 5. SECURITY CHECKS
    // ============================================
    echo "<h2>5. Security Analysis</h2>";
    echo "<div class='section'>";
    
    // Check for SQL injection risks - look for actual dangerous patterns
    // Pattern 1: Direct string concatenation in SQL (e.g., "SELECT * FROM table WHERE id = " . $_GET['id'])
    $sqlRisks1 = preg_match_all('/(?:SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\s+[^;]*["\']\s*\.\s*\$_(?:GET|POST|REQUEST)/i', $apiContent);
    
    // Pattern 2: SQL queries with $_GET/$_POST directly in query string (not in prepared statements)
    $sqlRisks2 = preg_match_all('/(?:query|exec)\s*\(\s*["\'][^"\']*\$_(?:GET|POST|REQUEST)\[.*\]/i', $apiContent);
    
    // Pattern 3: mysqli_query with string interpolation (dangerous)
    $sqlRisks3 = preg_match_all('/mysqli_query\s*\([^,]+,\s*["\'][^"\']*\$_(?:GET|POST|REQUEST)\[.*\]/i', $apiContent);
    
    // Pattern 4: Check for prepared statements usage (good practice)
    $preparedStmtCount = preg_match_all('/->prepare\s*\(/i', $apiContent);
    $executeCount = preg_match_all('/->execute\s*\(/i', $apiContent);
    
    $totalRisks = $sqlRisks1 + $sqlRisks2 + $sqlRisks3;
    
    if ($totalRisks > 0) {
        $warnings[] = "Potential SQL injection risks detected: $totalRisks pattern(s) found";
        echo "<div class='warning'>⚠️ <strong>Potential SQL injection risks detected:</strong><ul>";
        if ($sqlRisks1 > 0) echo "<li>String concatenation in SQL queries: $sqlRisks1</li>";
        if ($sqlRisks2 > 0) echo "<li>Direct use of \$_GET/\$_POST in query()/exec(): $sqlRisks2</li>";
        if ($sqlRisks3 > 0) echo "<li>mysqli_query with user input: $sqlRisks3</li>";
        echo "</ul></div>";
    } else {
        echo "<div class='success'>✅ No obvious SQL injection patterns detected</div>";
    }
    
    // Show prepared statement usage statistics
    echo "<div class='info'>ℹ️ <strong>Security Best Practices:</strong><ul>";
    echo "<li>Prepared statements found: $preparedStmtCount</li>";
    echo "<li>Execute calls found: $executeCount</li>";
    if ($preparedStmtCount > 0 && $executeCount > 0) {
        echo "<li>✅ Good: Using prepared statements (PDO::prepare + execute)</li>";
    }
    echo "</ul></div>";
    
    // Check for XSS risks
    $xssRisks = preg_match_all('/echo\s+\$_(?:GET|POST|REQUEST)\[.*\]/i', $apiContent);
    if ($xssRisks > 0) {
        $warnings[] = "Potential XSS risks detected";
        echo "<div class='warning'>⚠️ Potential XSS risks: Direct echo of user input detected</div>";
    } else {
        echo "<div class='success'>✅ No obvious XSS patterns detected</div>";
    }
    
    // Check session security
    if (strpos($dashboardContent, 'session_start()') !== false && strpos($apiContent, 'session_start()') !== false) {
        echo "<div class='success'>✅ Session management is implemented</div>";
    }
    
    echo "</div>";

    // ============================================
    // 6. FILE STRUCTURE CHECK
    // ============================================
    echo "<h2>6. File Structure & Dependencies</h2>";
    echo "<div class='section'>";
    
    $requiredFiles = ['dashboard.php', 'api.php', 'db.php', 'config.php', 'helpers.php', 'index.php'];
    $missingFiles = [];
    
    foreach ($requiredFiles as $file) {
        if (!file_exists($file)) {
            $missingFiles[] = $file;
        }
    }
    
    if (!empty($missingFiles)) {
        $errors[] = "Missing required files: " . implode(', ', $missingFiles);
        echo "<div class='error'>❌ <strong>MISSING FILES:</strong> " . implode(', ', $missingFiles) . "</div>";
    } else {
        echo "<div class='success'>✅ All required files exist</div>";
    }
    
    // Check for includes/requires
    preg_match_all('/(?:require|include)(?:_once)?\s+["\']([^"\']+)["\']/i', $dashboardContent . $apiContent, $includes);
    $includedFiles = $includes[1] ?? [];
    $missingIncludes = [];
    
    foreach (array_unique($includedFiles) as $file) {
        if (!file_exists($file)) {
            $missingIncludes[] = $file;
        }
    }
    
    if (!empty($missingIncludes)) {
        $errors[] = "Missing included files: " . implode(', ', $missingIncludes);
        echo "<div class='error'>❌ <strong>MISSING INCLUDED FILES:</strong> " . implode(', ', $missingIncludes) . "</div>";
    } else {
        echo "<div class='success'>✅ All included files exist</div>";
    }
    
    echo "</div>";

    // ============================================
    // 7. PERFORMANCE CHECKS
    // ============================================
    echo "<h2>7. Performance Analysis</h2>";
    echo "<div class='section'>";
    
    // Check for N+1 query patterns - look for foreach loops with database queries inside
    // Use multiline mode to match across lines
    $loopPatterns = preg_match_all('/foreach\s*\([^)]+\)\s*\{[\s\S]*?\$pdo->(?:prepare|query|exec)\s*\(/i', $apiContent, $n1Matches);
    $n1Count = count($n1Matches[0] ?? []);
    
    if ($n1Count > 0) {
        $warnings[] = "Potential N+1 query patterns detected: $n1Count instance(s)";
        echo "<div class='warning'>⚠️ <strong>Potential N+1 Query Patterns:</strong> $n1Count instance(s) found</div>";
        echo "<div class='info'>ℹ️ <strong>What is N+1 Query Problem?</strong><br>";
        echo "When you loop through items and make a database query for each item, you end up making N+1 queries (1 to fetch all items, then N queries for each item).<br>";
        echo "<strong>Solution:</strong> Use batch queries with IN clauses or JOIN queries to fetch all data at once.<br>";
        echo "See <code>PERFORMANCE_OPTIMIZATION.md</code> for detailed solutions.</div>";
    } else {
        echo "<div class='success'>✅ No obvious N+1 query patterns detected</div>";
    }
    
    // Check for missing indexes (basic check)
    echo "<div class='info'>ℹ️ Consider adding database indexes for frequently queried columns</div>";
    
    // Check for large file sizes
    $dashboardSize = filesize('dashboard.php');
    if ($dashboardSize > 500000) { // > 500KB
        $warnings[] = "dashboard.php is very large (" . round($dashboardSize/1024) . "KB) - consider splitting";
        echo "<div class='warning'>⚠️ dashboard.php is large (" . round($dashboardSize/1024) . "KB) - consider code splitting</div>";
    }
    
    echo "</div>";

    // ============================================
    // SUMMARY
    // ============================================
    $stats['issues_found'] = count($errors) + count($warnings);
    
    echo "<h2>📊 Summary Report</h2>";
    echo "<div class='stats'>";
    echo "<div class='stat-box'><h3>" . $stats['functions'] . "</h3><p>JavaScript Functions</p></div>";
    echo "<div class='stat-box'><h3>" . $stats['buttons'] . "</h3><p>Button Handlers</p></div>";
    echo "<div class='stat-box'><h3>" . $stats['api_endpoints'] . "</h3><p>API Endpoints</p></div>";
    echo "<div class='stat-box'><h3>" . $stats['issues_found'] . "</h3><p>Issues Found</p></div>";
    echo "</div>";
    
    echo "<div class='section'>";
    echo "<h3>Issue Breakdown</h3>";
    echo "<p><span class='badge badge-error'>Errors: " . count($errors) . "</span> ";
    echo "<span class='badge badge-warning'>Warnings: " . count($warnings) . "</span> ";
    echo "<span class='badge badge-success'>Info: " . count($info) . "</span></p>";
    
    if (empty($errors) && empty($warnings)) {
        echo "<div class='success'><strong>🎉 Great! No critical issues found. System appears healthy.</strong></div>";
    } else {
        if (!empty($errors)) {
            echo "<h4>❌ Critical Errors (" . count($errors) . "):</h4><ul>";
            foreach ($errors as $error) {
                echo "<li>" . htmlspecialchars($error) . "</li>";
            }
            echo "</ul>";
        }
        
        if (!empty($warnings)) {
            echo "<h4>⚠️ Warnings (" . count($warnings) . "):</h4><ul>";
            foreach ($warnings as $warning) {
                echo "<li>" . htmlspecialchars($warning) . "</li>";
            }
            echo "</ul>";
        }
    }
    echo "</div>";
    
    // Export option
    echo "<div class='section'>";
    echo "<h3>Export Report</h3>";
    echo "<button onclick='window.print()'>🖨️ Print Report</button>";
    echo "<button onclick='downloadReport()'>💾 Download as Text</button>";
    echo "</div>";
    ?>
    
    <script>
    function downloadReport() {
        const content = document.body.innerText;
        const blob = new Blob([content], { type: 'text/plain' });
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'bug_report_<?php echo date('Y-m-d_His'); ?>.txt';
        a.click();
        window.URL.revokeObjectURL(url);
    }
    </script>
</div>
</body>
</html>
