<?php
/**
 * Server-side helpers for shop SSR (shop-entry.php).
 * Requires: api/firebase-rtdb-admin.php, api/firebase-admin-bootstrap.local.php (on server).
 */

declare(strict_types=1);

/**
 * @return array{service_account_json_path?: string, firebase_database_url?: string}|null
 */
function ssr_shop_load_firebase_config(): ?array {
    $bootPath = __DIR__ . '/firebase-admin-bootstrap.local.php';
    if (!is_file($bootPath) || !is_readable($bootPath)) {
        return null;
    }
    $cfg = include $bootPath;
    if (!is_array($cfg)) {
        return null;
    }
    $jsonPath = isset($cfg['service_account_json_path']) ? (string) $cfg['service_account_json_path'] : '';
    $dbUrl = isset($cfg['firebase_database_url']) ? (string) $cfg['firebase_database_url'] : '';
    if ($jsonPath === '' || $dbUrl === '') {
        return null;
    }
    return [
        'service_account_json_path' => $jsonPath,
        'firebase_database_url' => rtrim($dbUrl, '/'),
    ];
}

/**
 * Read ?site= first; else first subdomain label if host has 3+ labels and not "www".
 */
function ssr_shop_resolve_site_key(): string {
    $q = isset($_GET['site']) ? trim((string) $_GET['site']) : '';
    if ($q !== '') {
        return $q;
    }
    $host = isset($_SERVER['HTTP_HOST']) ? (string) $_SERVER['HTTP_HOST'] : '';
    $host = preg_replace('/:\d+$/', '', $host) ?? '';
    if ($host === '' || $host === 'localhost') {
        return '';
    }
    $parts = explode('.', strtolower($host));
    if (count($parts) >= 3 && $parts[0] !== 'www') {
        return $parts[0];
    }
    return '';
}

/**
 * @return array{clientId?: string, error?: string}
 */
function ssr_shop_resolve_client_id(string $databaseUrl, string $accessToken, string $siteKey): array {
    $siteKey = trim($siteKey);
    if ($siteKey === '') {
        return ['error' => 'empty_site'];
    }
    $map = firebase_rtdb_get($databaseUrl, 'publicSiteMappings/' . $siteKey, $accessToken);
    if (!empty($map['error'])) {
        return ['error' => (string) $map['error']];
    }
    $id = $map['data'] ?? null;
    if ($id === null || $id === '') {
        return ['error' => 'mapping_not_found'];
    }
    return ['clientId' => (string) $id];
}

/**
 * Normalize RTDB categoryOrder (array or numeric-keyed object) to string[].
 *
 * @param mixed $orderVal
 * @return array<int, string>
 */
function ssr_shop_parse_category_order($orderVal): array {
    if ($orderVal === null) {
        return [];
    }
    if (!is_array($orderVal)) {
        return [];
    }
    if (function_exists('array_is_list') && array_is_list($orderVal)) {
        $out = [];
        foreach ($orderVal as $v) {
            if ($v !== null && $v !== '' && is_scalar($v)) {
                $out[] = (string) $v;
            }
        }
        return $out;
    }
    $keys = array_keys($orderVal);
    sort($keys, SORT_NUMERIC);
    $out = [];
    foreach ($keys as $k) {
        $v = $orderVal[$k] ?? null;
        if ($v !== null && $v !== '' && is_scalar($v)) {
            $out[] = (string) $v;
        }
    }
    return $out;
}

/**
 * Pick newest N products (by createdAt) from RTDB object map.
 *
 * @param mixed $productsVal
 * @return array<string, mixed>
 */
function ssr_shop_slice_products_preview($productsVal, int $limit = 10): array {
    if (!is_array($productsVal) || $productsVal === []) {
        return [];
    }
    $entries = [];
    foreach ($productsVal as $pid => $row) {
        if (!is_array($row)) {
            continue;
        }
        $ca = isset($row['createdAt']) ? (int) $row['createdAt'] : 0;
        $entries[] = ['id' => (string) $pid, 'createdAt' => $ca, 'row' => $row];
    }
    usort($entries, static function ($a, $b) {
        return ($b['createdAt'] <=> $a['createdAt']);
    });
    $out = [];
    $n = 0;
    foreach ($entries as $e) {
        if ($n >= $limit) {
            break;
        }
        $out[(string) $e['id']] = $e['row'];
        $n++;
    }
    return $out;
}

/**
 * @return array{payload?: array<string, mixed>, error?: string}
 */
function ssr_shop_build_initial_state(string $clientId, string $databaseUrl, string $accessToken, int $previewLimit = 10): array {
    $settingsRes = firebase_rtdb_get($databaseUrl, 'clients/' . $clientId . '/siteSettings', $accessToken);
    if (!empty($settingsRes['error'])) {
        return ['error' => 'settings:' . (string) $settingsRes['error']];
    }
    $settings = is_array($settingsRes['data'] ?? null) ? $settingsRes['data'] : [];

    $productsRes = firebase_rtdb_get($databaseUrl, 'clients/' . $clientId . '/products', $accessToken);
    if (!empty($productsRes['error'])) {
        return ['error' => 'products:' . (string) $productsRes['error']];
    }
    $productsVal = $productsRes['data'] ?? null;
    $preview = ssr_shop_slice_products_preview($productsVal, $previewLimit);

    $catsVal = null;
    $catsRes = firebase_rtdb_get($databaseUrl, 'clients/' . $clientId . '/categories', $accessToken);
    if (empty($catsRes['error']) && is_array($catsRes['data'] ?? null)) {
        $catsVal = $catsRes['data'];
    }

    $categoryOrder = [];
    $orderRes = firebase_rtdb_get($databaseUrl, 'clients/' . $clientId . '/categoryOrder', $accessToken);
    if (empty($orderRes['error'])) {
        $categoryOrder = ssr_shop_parse_category_order($orderRes['data'] ?? null);
    }

    return [
        'payload' => [
            'clientId' => $clientId,
            'settings' => $settings,
            'productsVal' => $preview,
            'catsVal' => $catsVal,
            'categoryOrder' => $categoryOrder,
        ],
    ];
}

/**
 * File cache for SSR JSON payload (short TTL).
 *
 * @return array<string, mixed>|null
 */
function ssr_shop_cache_get(string $cacheKey, int $ttlSeconds = 90): ?array {
    $dir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'ssr-cache';
    if (!is_dir($dir)) {
        @mkdir($dir, 0775, true);
    }
    $path = $dir . DIRECTORY_SEPARATOR . preg_replace('/[^a-f0-9]/i', '', $cacheKey) . '.json';
    if (!is_file($path)) {
        return null;
    }
    $age = time() - (int) filemtime($path);
    if ($age > $ttlSeconds) {
        @unlink($path);
        return null;
    }
    $raw = @file_get_contents($path);
    if (!is_string($raw) || $raw === '') {
        return null;
    }
    $data = json_decode($raw, true);
    return is_array($data) ? $data : null;
}

function ssr_shop_cache_set(string $cacheKey, array $payload): void {
    $dir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'ssr-cache';
    if (!is_dir($dir)) {
        @mkdir($dir, 0775, true);
    }
    $safe = preg_replace('/[^a-f0-9]/i', '', $cacheKey);
    if ($safe === '') {
        return;
    }
    $path = $dir . DIRECTORY_SEPARATOR . $safe . '.json';
    @file_put_contents($path, json_encode($payload, JSON_UNESCAPED_UNICODE), LOCK_EX);
}

function ssr_shop_cache_key(string $clientId, string $siteKey): string {
    return sha1($clientId . '|' . $siteKey . '|v2');
}
