'error', 'message' => 'Unauthorized']); exit; } $requestedDate = filterRequest('date') ?: date('Y-m-d'); $section = filterRequest('section') ?: 'all'; if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $requestedDate)) { http_response_code(400); echo json_encode(['status' => 'error', 'message' => 'Invalid date format']); exit; } $cacheBase = __DIR__ . '/../../../cache/analytics'; $dayDir = "$cacheBase/$requestedDate"; $response = [ 'status' => 'success', 'date' => $requestedDate, 'section' => $section, 'data' => [], ]; function loadSnapshot(string $dir, string $name): ?array { $path = "$dir/$name.json"; if (!file_exists($path)) return null; $data = json_decode(file_get_contents($path), true); return is_array($data) ? $data : null; } function loadLatestRealtime(string $dir): ?array { $files = glob("$dir/realtime_*.json"); if (empty($files)) return null; sort($files); $latest = end($files); $data = json_decode(file_get_contents($latest), true); return is_array($data) ? $data : null; } $sectionMap = [ 'realtime' => fn() => loadLatestRealtime($dayDir), 'gap' => fn() => loadSnapshot($dayDir, 'supply_demand_gap'), 'heatmap' => fn() => loadSnapshot($dayDir, 'heatmap'), 'pricing' => fn() => loadSnapshot($dayDir, 'pricing_grids'), 'demand' => fn() => loadSnapshot($dayDir, 'predictive_demand'), 'revenue' => fn() => loadSnapshot($dayDir, 'revenue_30d'), 'growth' => fn() => loadSnapshot($dayDir, 'growth_30d'), 'market' => fn() => loadSnapshot($dayDir, 'market_health'), 'complaints' => fn() => loadSnapshot($dayDir, 'complaints_open'), 'funnel' => fn() => loadSnapshot($dayDir, 'ride_funnel'), 'hourly' => fn() => loadSnapshot($dayDir, 'hourly_pattern'), 'weekly' => fn() => loadSnapshot($dayDir, 'weekly_comparison'), 'zones' => fn() => loadSnapshot($dayDir, 'top_zones'), 'retention' => fn() => loadSnapshot($dayDir, 'retention_cohort'), 'competitor' => fn() => loadSnapshot($dayDir, 'competitor_prices_24h'), ]; try { if (!is_dir($dayDir)) { $response['data'] = null; $response['note'] = "No snapshot data for $requestedDate"; $indexPath = "$cacheBase/index.json"; if (file_exists($indexPath)) { $idx = json_decode(file_get_contents($indexPath), true); $response['available_dates'] = $idx['available_dates'] ?? []; } echo json_encode($response, JSON_UNESCAPED_UNICODE); exit; } if ($section === 'all') { foreach ($sectionMap as $key => $loader) { $result = $loader(); if ($result !== null) { $response['data'][$key] = $result; } } } elseif (isset($sectionMap[$section])) { $response['data'] = $sectionMap[$section](); } else { http_response_code(400); echo json_encode([ 'status' => 'error', 'message' => "Unknown section: $section", 'available' => array_keys($sectionMap), ]); exit; } $indexPath = "$cacheBase/index.json"; if (file_exists($indexPath)) { $idx = json_decode(file_get_contents($indexPath), true); $response['available_dates'] = $idx['available_dates'] ?? []; } echo json_encode($response, JSON_UNESCAPED_UNICODE); } catch (Exception $e) { http_response_code(500); error_log("[dashboard_data.php] " . $e->getMessage()); echo json_encode(['status' => 'error', 'message' => 'Internal error']); }