<?php

if (!function_exists('mdns_normalize_base_url')) {
    function mdns_normalize_base_url(string $url): string {
        $url = trim($url);
        if ($url === '') return '';
        if (!preg_match('#^https?://#i', $url)) {
            $url = 'http://' . $url;
        }
        $parts = @parse_url($url);
        if (!is_array($parts) || empty($parts['host'])) {
            return rtrim($url, '/');
        }
        $scheme = strtolower($parts['scheme'] ?? 'http');
        $host = strtolower($parts['host']);
        $port = isset($parts['port']) ? ':' . $parts['port'] : '';
        $path = trim((string)($parts['path'] ?? ''));
        if ($path === '/get.php' || $path === '/player_api.php') {
            $path = '';
        }
        return rtrim($scheme . '://' . $host . $port . $path, '/');
    }
}

if (!function_exists('mdns_extract_credentials')) {
    function mdns_extract_credentials(array $playlistData): array {
        $playlistUrl = trim((string)($playlistData['playlist_url'] ?? $playlistData['url'] ?? ''));
        $username = trim((string)($playlistData['username'] ?? ''));
        $password = trim((string)($playlistData['password'] ?? ''));
        $baseUrl = trim((string)($playlistData['base_url'] ?? $playlistData['server_url'] ?? ''));

        if ($playlistUrl !== '') {
            $parts = @parse_url($playlistUrl);
            if (is_array($parts)) {
                $query = [];
                parse_str((string)($parts['query'] ?? ''), $query);
                if ($username === '' && !empty($query['username'])) {
                    $username = trim((string)$query['username']);
                }
                if ($password === '' && !empty($query['password'])) {
                    $password = trim((string)$query['password']);
                }
                if ($baseUrl === '' && !empty($parts['scheme']) && !empty($parts['host'])) {
                    $baseUrl = mdns_normalize_base_url(($parts['scheme'] ?? 'http') . '://' . $parts['host'] . (isset($parts['port']) ? ':' . $parts['port'] : ''));
                }
            }
        }

        return [
            'playlist_url' => $playlistUrl,
            'base_url' => mdns_normalize_base_url($baseUrl),
            'username' => $username,
            'password' => $password,
        ];
    }
}

if (!function_exists('mdns_build_playlist_url')) {
    function mdns_build_playlist_url(string $baseUrl, string $username, string $password): string {
        $baseUrl = mdns_normalize_base_url($baseUrl);
        return $baseUrl . '/get.php?username=' . rawurlencode($username) . '&password=' . rawurlencode($password) . '&type=m3u_plus&output=ts';
    }
}

if (!function_exists('mdns_find_dns_row')) {
    function mdns_find_dns_row(array $dnsRows, $dnsId = null, string $baseUrl = '', string $title = ''): ?array {
        $normalizedBase = mdns_normalize_base_url($baseUrl);
        $normalizedTitle = trim(function_exists('mb_strtolower') ? mb_strtolower($title) : strtolower($title));
        foreach ($dnsRows as $row) {
            if ($dnsId !== null && $dnsId !== '' && (string)$row['id'] === (string)$dnsId) {
                return $row;
            }
            if ($normalizedBase !== '' && mdns_normalize_base_url((string)($row['url'] ?? '')) === $normalizedBase) {
                return $row;
            }
            if ($normalizedTitle !== '' && trim(function_exists('mb_strtolower') ? mb_strtolower((string)($row['title'] ?? '')) : strtolower((string)($row['title'] ?? ''))) === $normalizedTitle) {
                return $row;
            }
        }
        return null;
    }
}

if (!function_exists('mdns_upsert_playlist')) {
    function mdns_upsert_playlist(SQLiteWrapper $db, int $dnsId, string $macAddress, string $username, string $password, string $pin = '0000', ?string $link = null): void {
        if ($dnsId <= 0 || $macAddress === '' || $username === '' || $password === '') {
            return;
        }

        $existing = $db->select(
            'playlist',
            '*',
            'dns_id = :dns_id AND mac_address = :mac_address',
            '',
            [':dns_id' => $dnsId, ':mac_address' => $macAddress]
        );

        $data = [
            'username' => $username,
            'password' => $password,
            'pin' => ($pin !== '' ? $pin : '0000'),
            'last_used' => time(),
        ];

        if ($link !== null) {
            $data['link'] = $link;
        }

        if (!empty($existing)) {
            $db->update('playlist', $data, 'dns_id = :dns_id AND mac_address = :mac_address', [':dns_id' => $dnsId, ':mac_address' => $macAddress]);
            return;
        }

        $insert = [
            'dns_id' => $dnsId,
            'mac_address' => $macAddress,
            'username' => $username,
            'password' => $password,
            'pin' => ($pin !== '' ? $pin : '0000'),
            'last_used' => time(),
        ];
        if ($link !== null) {
            $insert['link'] = $link;
        }
        $db->insert('playlist', $insert);
    }
}

if (!function_exists('mdns_probe_dns_batch')) {
    function mdns_probe_dns_batch(array $dnsRows, string $username, string $password, int $timeoutSeconds = 5, int $maxConcurrency = 5): array {
        $results = [];
        if ($username === '' || $password === '' || empty($dnsRows) || !function_exists('curl_multi_init')) {
            return $results;
        }

        $chunks = array_chunk($dnsRows, max(1, $maxConcurrency));
        foreach ($chunks as $chunk) {
            $multi = curl_multi_init();
            $handles = [];

            foreach ($chunk as $dnsRow) {
                $baseUrl = mdns_normalize_base_url((string)($dnsRow['url'] ?? ''));
                if ($baseUrl === '') {
                    continue;
                }
                $probeUrl = $baseUrl . '/player_api.php?username=' . rawurlencode($username) . '&password=' . rawurlencode($password);
                $ch = curl_init();
                curl_setopt_array($ch, [
                    CURLOPT_URL => $probeUrl,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_CONNECTTIMEOUT => min(3, $timeoutSeconds),
                    CURLOPT_TIMEOUT => $timeoutSeconds,
                    CURLOPT_SSL_VERIFYPEER => false,
                    CURLOPT_SSL_VERIFYHOST => false,
                    CURLOPT_USERAGENT => 'IBO4-MultiDNS/1.0',
                    CURLOPT_HTTPHEADER => ['Accept: application/json'],
                ]);
                curl_multi_add_handle($multi, $ch);
                $handles[(int)$ch] = [$ch, $dnsRow, $baseUrl];
            }

            do {
                $status = curl_multi_exec($multi, $running);
                if ($running) {
                    curl_multi_select($multi, 1.0);
                }
            } while ($running && $status === CURLM_OK);

            foreach ($handles as [$ch, $dnsRow, $baseUrl]) {
                $body = (string)curl_multi_getcontent($ch);
                $httpCode = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
                $ok = false;
                if ($httpCode >= 200 && $httpCode < 300 && $body !== '') {
                    $decoded = json_decode($body, true);
                    if (is_array($decoded)) {
                        $ok = (
                            (isset($decoded['user_info']['auth']) && (string)$decoded['user_info']['auth'] === '1') ||
                            (isset($decoded['auth']) && (string)$decoded['auth'] === '1') ||
                            (!empty($decoded['user_info']) && empty($decoded['user_info']['status'])) ||
                            (!empty($decoded['server_info']))
                        );
                    }
                }
                $results[(int)$dnsRow['id']] = [
                    'dns' => $dnsRow,
                    'ok' => $ok,
                    'base_url' => $baseUrl,
                    'http_code' => $httpCode,
                ];
                curl_multi_remove_handle($multi, $ch);
                curl_close($ch);
            }

            curl_multi_close($multi);
        }

        return $results;
    }
}

if (!function_exists('mdns_collect_explicit_base_urls')) {
    function mdns_collect_explicit_base_urls($value): array {
        $baseUrls = [];
        if (is_string($value) && $value !== '') {
            $decoded = json_decode($value, true);
            if (is_array($decoded)) {
                $value = $decoded;
            } else {
                $value = preg_split('/\s*,\s*/', $value);
            }
        }
        if (is_array($value)) {
            foreach ($value as $item) {
                $url = '';
                if (is_string($item)) {
                    $url = $item;
                } elseif (is_array($item)) {
                    $url = (string)($item['base_url'] ?? $item['url'] ?? '');
                }
                $normalized = mdns_normalize_base_url($url);
                if ($normalized !== '') {
                    $baseUrls[$normalized] = $normalized;
                }
            }
        }
        return array_values($baseUrls);
    }
}

if (!function_exists('mdns_sync_playlist_to_other_dns')) {
    function mdns_sync_playlist_to_other_dns(SQLiteWrapper $db, string $macAddress, string $username, string $password, array $options = []): array {
        $pin = (string)($options['pin'] ?? '0000');
        $link = array_key_exists('link', $options) ? $options['link'] : null;
        $primaryDnsId = isset($options['primary_dns_id']) ? (int)$options['primary_dns_id'] : 0;
        $primaryBaseUrl = mdns_normalize_base_url((string)($options['primary_base_url'] ?? ''));
        $explicitBaseUrls = mdns_collect_explicit_base_urls($options['all_base_urls'] ?? []);

        $dnsRows = $db->select('dns', '*', '', 'id ASC');
        if (empty($dnsRows)) {
            return ['saved_dns_ids' => [], 'active_dns_ids' => [], 'tested_dns_ids' => []];
        }

        $savedIds = [];
        $activeIds = [];
        $testedIds = [];

        $primaryRow = mdns_find_dns_row($dnsRows, $primaryDnsId > 0 ? $primaryDnsId : null, $primaryBaseUrl);
        if ($primaryRow) {
            mdns_upsert_playlist($db, (int)$primaryRow['id'], $macAddress, $username, $password, $pin, $link);
            $savedIds[(int)$primaryRow['id']] = (int)$primaryRow['id'];
            $activeIds[(int)$primaryRow['id']] = (int)$primaryRow['id'];
        }

        if (!empty($explicitBaseUrls)) {
            foreach ($explicitBaseUrls as $baseUrl) {
                $row = mdns_find_dns_row($dnsRows, null, $baseUrl);
                if ($row) {
                    $dnsId = (int)$row['id'];
                    mdns_upsert_playlist($db, $dnsId, $macAddress, $username, $password, $pin, $link);
                    $savedIds[$dnsId] = $dnsId;
                    $activeIds[$dnsId] = $dnsId;
                    $testedIds[$dnsId] = $dnsId;
                }
            }
            return [
                'saved_dns_ids' => array_values($savedIds),
                'active_dns_ids' => array_values($activeIds),
                'tested_dns_ids' => array_values($testedIds),
                'mode' => 'explicit_base_urls',
            ];
        }

        $probes = mdns_probe_dns_batch($dnsRows, $username, $password, 5, 5);
        foreach ($probes as $dnsId => $probe) {
            $testedIds[$dnsId] = $dnsId;
            if (!empty($probe['ok'])) {
                mdns_upsert_playlist($db, (int)$dnsId, $macAddress, $username, $password, $pin, $link);
                $savedIds[(int)$dnsId] = (int)$dnsId;
                $activeIds[(int)$dnsId] = (int)$dnsId;
            }
        }

        return [
            'saved_dns_ids' => array_values($savedIds),
            'active_dns_ids' => array_values($activeIds),
            'tested_dns_ids' => array_values($testedIds),
            'mode' => 'panel_probe',
        ];
    }
}
