<?php
declare(strict_types=1);

const MOCKER_SLOT_API_ROULETTE = 'https://api.rxhbgdnjdkgfdjshsdghsf.net/api/client/slot-games/roulette';
const MOCKER_SLOT_API_ORIGIN = 'https://api.rxhbgdnjdkgfdjshsdghsf.net';

/** @var list<array{id: string, label: string}> */
const MOCKER_SLOT_PROVIDERS = [
    ['id' => 'pragmaticplay', 'label' => 'Pragmatic Play'],
];

function mocker_slot_is_list_array(array $arr): bool
{
    if ($arr === []) {
        return true;
    }
    $i = 0;
    foreach ($arr as $k => $_) {
        if ($k !== $i) {
            return false;
        }
        $i++;
    }

    return true;
}

/**
 * @param list<string> $headers
 */
function mocker_slot_http_get_attempt(string $url, array $headers, int $timeoutSec = 20): ?string
{
    if (!function_exists('curl_init')) {
        $ctx = stream_context_create([
            'http' => [
                'method' => 'GET',
                'header' => implode("\r\n", $headers),
                'timeout' => $timeoutSec,
            ],
            'ssl' => [
                'verify_peer' => false,
                'verify_peer_name' => false,
            ],
        ]);
        $body = @file_get_contents($url, false, $ctx);

        return mocker_slot_http_body_ok($body, 200);
    }

    foreach ([true, false] as $verifySsl) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_TIMEOUT => $timeoutSec,
            CURLOPT_CONNECTTIMEOUT => min(12, $timeoutSec),
            CURLOPT_SSL_VERIFYPEER => $verifySsl,
            CURLOPT_SSL_VERIFYHOST => $verifySsl ? 2 : 0,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_ENCODING => '',
        ]);
        $body = curl_exec($ch);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $ok = mocker_slot_http_body_ok($body, $code);
        if ($ok !== null) {
            return $ok;
        }
    }

    return null;
}

function mocker_slot_http_body_ok(mixed $body, int $code): ?string
{
    if (!is_string($body) || $body === '' || mocker_slot_body_looks_like_html($body)) {
        return null;
    }
    if ($code >= 200 && $code < 300) {
        return $body;
    }
    if ($code >= 400 && $code < 600 && mocker_slot_body_looks_like_json($body)) {
        return $body;
    }

    return null;
}

function mocker_slot_body_looks_like_json(string $body): bool
{
    $t = ltrim($body);

    return $t !== '' && ($t[0] === '{' || $t[0] === '[');
}

function mocker_slot_http_get(string $url): ?string
{
    $isCli = PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg';
    $ua = trim((string) ($_SERVER['HTTP_USER_AGENT'] ?? ''));
    if ($ua === '' || stripos($ua, 'curl') !== false || stripos($ua, 'php') !== false) {
        $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
    }

    $chrome = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';

    $profiles = [
        [
            'Accept: application/json, text/plain, */*',
            'Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7',
            'User-Agent: ' . $ua,
            'Origin: ' . MOCKER_SLOT_API_ORIGIN,
            'Referer: ' . MOCKER_SLOT_API_ORIGIN . '/',
        ],
        [
            'Accept: application/json',
            'User-Agent: ' . $chrome,
            'Origin: https://mocker27.com',
            'Referer: https://mocker27.com/',
        ],
    ];

    if (!$isCli) {
        $profiles = [$profiles[0]];
    }

    $timeout = $isCli ? 40 : 18;
    $attempts = $isCli ? 2 : 1;

    foreach ($profiles as $headers) {
        for ($attempt = 0; $attempt < $attempts; $attempt++) {
            if ($attempt > 0) {
                usleep(300000);
            }
            $body = mocker_slot_http_get_attempt($url, $headers, $timeout);
            if ($body !== null) {
                return $body;
            }
        }
    }

    return null;
}

function mocker_slot_body_looks_like_html(string $body): bool
{
    $head = ltrim(substr($body, 0, 256));
    if ($head === '') {
        return true;
    }
    if ($head[0] === '{' || $head[0] === '[') {
        return false;
    }

    return stripos($head, '<!DOCTYPE') !== false
        || stripos($head, '<html') !== false
        || stripos($head, 'Attention Required') !== false;
}

function mocker_slot_normalize_image_url(string $image): string
{
    $image = trim($image);
    if ($image === '') {
        return '';
    }
    if (preg_match('#^https?://#i', $image)) {
        return $image;
    }
    if (str_starts_with($image, '//')) {
        return 'https:' . $image;
    }
    if (str_starts_with($image, '/')) {
        return MOCKER_SLOT_API_ORIGIN . $image;
    }

    return MOCKER_SLOT_API_ORIGIN . '/' . ltrim($image, '/');
}

function mocker_slot_provider_label_from_id(string $id): string
{
    $id = trim($id);
    if ($id === '') {
        return '';
    }
    $pretty = preg_replace('/([a-z])([A-Z])/', '$1 $2', $id);
    $pretty = str_replace(['_', '-'], ' ', (string) $pretty);

    return ucwords(strtolower(trim($pretty)));
}

/**
 * @return list<array{id: string, label: string}>
 */
function mocker_slot_list_providers(): array
{
    static $cache = null;
    if ($cache !== null) {
        return $cache;
    }

    $path = dirname(__DIR__) . '/data/slot_providers.json';
    if (is_readable($path)) {
        $decoded = json_decode((string) file_get_contents($path), true);
        if (is_array($decoded) && is_array($decoded['providers'] ?? null)) {
            $out = [];
            foreach ($decoded['providers'] as $item) {
                if (!is_array($item)) {
                    continue;
                }
                $id = strtolower(preg_replace('/[^a-z0-9_-]/', '', (string) ($item['id'] ?? '')));
                if ($id === '') {
                    continue;
                }
                $label = trim((string) ($item['label'] ?? $item['name'] ?? ''));
                $out[] = [
                    'id' => $id,
                    'label' => $label !== '' ? $label : mocker_slot_provider_label_from_id($id),
                ];
            }
            if ($out !== []) {
                $cache = $out;

                return $cache;
            }
        }
    }

    $cache = MOCKER_SLOT_PROVIDERS;

    return $cache;
}

function mocker_slot_provider_label(string $providerId): string
{
    $key = strtolower(preg_replace('/[^a-z0-9_-]/', '', $providerId));
    foreach (mocker_slot_list_providers() as $p) {
        if ($p['id'] === $key) {
            return $p['label'];
        }
    }

    return mocker_slot_provider_label_from_id($key);
}

function mocker_slot_provider_is_allowed(string $providerId): bool
{
    $key = strtolower(preg_replace('/[^a-z0-9_-]/', '', $providerId));
    if ($key === '') {
        return false;
    }
    foreach (mocker_slot_list_providers() as $p) {
        if ($p['id'] === $key) {
            return true;
        }
    }

    return false;
}

/**
 * @return array{id: string, name: string, image: string, rtp: ?float}|null
 */
function mocker_slot_parse_one_game(array $g, int $index): ?array
{
    if (isset($g['game']) && is_array($g['game'])) {
        $nested = mocker_slot_parse_one_game($g['game'], $index);
        if ($nested !== null) {
            return $nested;
        }
    }

    if (isset($g['attributes']) && is_array($g['attributes'])) {
        $nested = mocker_slot_parse_one_game($g['attributes'], $index);
        if ($nested !== null) {
            return $nested;
        }
    }

    $name = trim((string) (
        $g['name']
        ?? $g['title']
        ?? $g['gameName']
        ?? $g['game_name']
        ?? $g['gameTitle']
        ?? $g['game_title']
        ?? $g['displayName']
        ?? $g['display_name']
        ?? $g['slotName']
        ?? $g['slot_name']
        ?? $g['label']
        ?? ''
    ));
    if ($name === '' && isset($g['translations']) && is_array($g['translations'])) {
        foreach (['tr', 'en', 'default'] as $loc) {
            $tr = $g['translations'][$loc] ?? null;
            if (is_array($tr)) {
                $name = trim((string) ($tr['name'] ?? $tr['title'] ?? ''));
                if ($name !== '') {
                    break;
                }
            }
        }
    }
    if ($name === '') {
        return null;
    }

    $image = trim((string) (
        $g['image']
        ?? $g['thumbnail']
        ?? $g['thumb']
        ?? $g['imageUrl']
        ?? $g['image_url']
        ?? $g['thumbnailUrl']
        ?? $g['thumbnail_url']
        ?? $g['banner']
        ?? $g['cover']
        ?? $g['icon']
        ?? $g['logo']
        ?? $g['picture']
        ?? $g['img']
        ?? $g['img_url']
        ?? $g['imgUrl']
        ?? $g['imgURL']
        ?? $g['poster']
        ?? $g['mobile_image']
        ?? $g['desktop_image']
        ?? $g['mobileImage']
        ?? $g['desktopImage']
        ?? ''
    ));
    if ($image === '' && isset($g['images']) && is_array($g['images'])) {
        $image = trim((string) (
            $g['images']['thumbnail']
            ?? $g['images']['cover']
            ?? $g['images'][0]
            ?? ''
        ));
    }
    $image = mocker_slot_normalize_image_url($image);

    $id = trim((string) (
        $g['id']
        ?? $g['gameId']
        ?? $g['game_id']
        ?? $g['slug']
        ?? $g['code']
        ?? $name
    ));
    if ($id === '') {
        $id = 'game-' . $index;
    }

    $rtpRaw = $g['rtp'] ?? $g['RTP'] ?? $g['rtpPercent'] ?? $g['rtp_percent'] ?? null;
    $rtp = null;
    if ($rtpRaw !== null && $rtpRaw !== '') {
        $rtpNum = (float) str_replace(',', '.', preg_replace('/[^0-9.,]/', '', (string) $rtpRaw));
        if ($rtpNum > 0 && $rtpNum <= 100) {
            $rtp = round($rtpNum, 2);
        }
    }

    return [
        'id' => $id,
        'name' => $name,
        'image' => $image,
        'rtp' => $rtp,
    ];
}

/**
 * @return list<array{id: string, name: string, image: string, rtp: ?float}>
 */
function mocker_slot_extract_games_from_list(array $list): array
{
    $out = [];
    $seen = [];
    $i = 0;
    foreach ($list as $item) {
        if (!is_array($item)) {
            continue;
        }
        $game = mocker_slot_parse_one_game($item, $i);
        $i++;
        if ($game === null) {
            continue;
        }
        $dedupeKey = strtolower($game['id'] . '|' . $game['name']);
        if (isset($seen[$dedupeKey])) {
            continue;
        }
        $seen[$dedupeKey] = true;
        $out[] = $game;
    }

    return $out;
}

/**
 * Liste veya slug => oyun map yapısı.
 *
 * @return list<array{id: string, name: string, image: string, rtp: ?float}>
 */
function mocker_slot_extract_games_from_collection(array $node): array
{
    if (mocker_slot_is_list_array($node)) {
        return mocker_slot_extract_games_from_list($node);
    }

    $out = [];
    $seen = [];
    $i = 0;
    foreach ($node as $key => $item) {
        if (!is_array($item)) {
            continue;
        }
        $game = mocker_slot_parse_one_game($item, $i);
        $i++;
        if ($game === null) {
            continue;
        }
        $slug = strtolower(preg_replace('/[^a-z0-9_-]/', '', (string) $key));
        if ($slug !== '' && !ctype_digit((string) $key)) {
            $game['id'] = $slug;
        }
        $dedupeKey = strtolower($game['id'] . '|' . $game['name']);
        if (isset($seen[$dedupeKey])) {
            continue;
        }
        $seen[$dedupeKey] = true;
        $out[] = $game;
    }

    return $out;
}

/**
 * @return list<array{id: string, name: string, image: string, rtp: ?float}>
 */
function mocker_slot_extract_games_deep(mixed $node, int $depth = 0): array
{
    if ($depth > 12 || !is_array($node)) {
        return [];
    }

    $try = mocker_slot_extract_games_from_collection($node);
    if (count($try) >= 1) {
        return $try;
    }

    foreach ($node as $v) {
        if (!is_array($v)) {
            continue;
        }
        $inner = mocker_slot_extract_games_deep($v, $depth + 1);
        if ($inner !== []) {
            return $inner;
        }
    }

    return [];
}

/**
 * @return list<array{id: string, name: string, image: string, rtp: ?float}>
 */
function mocker_slot_extract_games_list(mixed $node, int $depth = 0): array
{
    if ($depth > 6 || !is_array($node)) {
        return [];
    }

    if ($depth === 0) {
        $parsed = mocker_slot_extract_games_from_collection($node);
        if ($parsed !== []) {
            return $parsed;
        }
    }

    foreach (['games', 'items', 'results', 'list', 'slots', 'slotGames', 'slot_games', 'roulette', 'records', 'rouletteGames', 'slot_games_list'] as $key) {
        if (isset($node[$key]) && is_array($node[$key])) {
            $parsed = mocker_slot_extract_games_list($node[$key], $depth + 1);
            if ($parsed !== []) {
                return $parsed;
            }
        }
    }

    if (isset($node['data']) && is_array($node['data'])) {
        $parsed = mocker_slot_extract_games_list($node['data'], $depth + 1);
        if ($parsed !== []) {
            return $parsed;
        }
    }

    foreach (['result', 'payload', 'response', 'content', 'body'] as $key) {
        if (isset($node[$key]) && is_array($node[$key])) {
            $parsed = mocker_slot_extract_games_list($node[$key], $depth + 1);
            if ($parsed !== []) {
                return $parsed;
            }
        }
    }

    if (is_string($node['data'] ?? null)) {
        $inner = json_decode((string) $node['data'], true);
        if (is_array($inner)) {
            $parsed = mocker_slot_extract_games_list($inner, $depth + 1);
            if ($parsed !== []) {
                return $parsed;
            }
        }
    }

    return [];
}

function mocker_slot_save_raw_debug(string $provider, string $raw): void
{
    if (strlen($raw) > 800000) {
        return;
    }
    $path = mocker_slot_games_cache_path($provider) . '.raw.txt';
    $dir = dirname($path);
    if (!is_dir($dir)) {
        @mkdir($dir, 0755, true);
    }
    @file_put_contents($path, $raw, LOCK_EX);
}

function mocker_slot_games_cache_path(string $provider): string
{
    $safe = preg_replace('/[^a-z0-9_-]/', '', strtolower($provider));

    return dirname(__DIR__) . '/data/cache/slot_roulette/' . $safe . '.json';
}

/**
 * @param list<array{id: string, name: string, image: string, rtp: ?float}> $games
 */
function mocker_slot_save_games_cache(string $provider, array $games): void
{
    if ($games === []) {
        return;
    }
    $path = mocker_slot_games_cache_path($provider);
    $dir = dirname($path);
    if (!is_dir($dir)) {
        @mkdir($dir, 0755, true);
    }
    $payload = json_encode([
        'provider' => $provider,
        'games' => $games,
        'updatedAt' => gmdate('c'),
    ], JSON_UNESCAPED_UNICODE);
    if ($payload !== false) {
        @file_put_contents($path, $payload, LOCK_EX);
    }
}

/**
 * @return list<array{id: string, name: string, image: string, rtp: ?float}>
 */
function mocker_slot_read_games_cache(string $provider): array
{
    $path = mocker_slot_games_cache_path($provider);
    if (!is_readable($path)) {
        return [];
    }
    $decoded = json_decode((string) file_get_contents($path), true);
    if (!is_array($decoded)) {
        return [];
    }

    return mocker_slot_extract_games_list($decoded['games'] ?? $decoded);
}

/**
 * @return list<array{id: string, name: string, image: string, rtp: ?float}>
 */
function mocker_slot_resolve_games(string $provider, ?string $rawJson): array
{
    if ($rawJson !== null && $rawJson !== '') {
        $decoded = json_decode($rawJson, true);
        if (is_array($decoded)) {
            $games = mocker_slot_extract_games_list($decoded);
            if ($games === []) {
                $games = mocker_slot_extract_games_deep($decoded);
            }
            if ($games !== []) {
                mocker_slot_save_games_cache($provider, $games);

                return $games;
            }
            mocker_slot_save_raw_debug($provider, $rawJson);
        }
    }

    $cached = mocker_slot_read_games_cache($provider);
    if ($cached !== []) {
        return $cached;
    }

    return mocker_slot_read_fallback($provider);
}

function mocker_slot_read_fallback(string $provider): array
{
    $path = dirname(__DIR__) . '/data/slot_games_fallback.json';
    if (!is_readable($path)) {
        return [];
    }
    $data = json_decode((string) file_get_contents($path), true);
    if (!is_array($data)) {
        return [];
    }
    $list = $data[$provider] ?? [];

    return is_array($list) ? mocker_slot_extract_games_list($list) : [];
}
