<?php
declare(strict_types=1);

function app_config(?string $key = null, mixed $default = null): mixed
{
    static $config;
    $config ??= require dirname(__DIR__) . '/config.php';
    if ($key === null) return $config;
    $value = $config;
    foreach (explode('.', $key) as $segment) {
        if (!is_array($value) || !array_key_exists($segment, $value)) return $default;
        $value = $value[$segment];
    }
    return $value;
}

function e(mixed $value): string
{
    return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

/**
 * Google Search Console HTML etiketi alanına ister yalnız doğrulama kodu,
 * ister Google'ın verdiği tam <meta> etiketi yapıştırılsın, yalnız güvenli
 * content değerini döndürür.
 */
function search_console_verification_token(string $value): string
{
    $value = trim(html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8'));
    if ($value === '') return '';

    $looksLikeMeta = str_contains(strtolower($value), 'google-site-verification')
        || str_starts_with(ltrim($value), '<meta');

    if ($looksLikeMeta) {
        if (preg_match('/\bcontent\s*=\s*(["\'])(.*?)\1/is', $value, $match)) {
            $value = (string) $match[2];
        } elseif (preg_match('/\bcontent\s*=\s*([^\s>]+)/i', $value, $match)) {
            $value = trim((string) $match[1], "\'\"");
        } else {
            return '';
        }
    }

    $value = trim(strip_tags($value));
    if (!preg_match('/^[A-Za-z0-9_-]{10,255}$/', $value)) return '';

    return $value;
}

function base_url(): string
{
    $configured = rtrim((string) app_config('app.base_url', ''), '/');
    if ($configured !== '') return $configured;
    $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https';
    return ($https ? 'https://' : 'http://') . ($_SERVER['HTTP_HOST'] ?? 'localhost');
}

function url(string $path = ''): string
{
    if (preg_match('~^https?://~i', $path)) return $path;
    return base_url() . '/' . ltrim($path, '/');
}

function asset(string $path): string
{
    $clean = ltrim($path, '/');
    $publicPath = dirname(__DIR__) . '/assets/' . $clean;
    $version = is_file($publicPath) ? (string) filemtime($publicPath) : '';
    return url('/assets/' . $clean) . ($version !== '' ? '?v=' . rawurlencode($version) : '');
}

function current_path(): string
{
    $path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
    return '/' . ltrim(rawurldecode($path), '/');
}

function current_url(): string { return url(current_path()); }

function redirect(string $to, int $status = 302): never
{
    header('Location: ' . (preg_match('~^https?://~', $to) ? $to : url($to)), true, $status);
    exit;
}

function flash(string $key, ?string $value = null): ?string
{
    if ($value !== null) {
        $_SESSION['_flash'][$key] = $value;
        return null;
    }
    $message = $_SESSION['_flash'][$key] ?? null;
    unset($_SESSION['_flash'][$key]);
    return $message;
}

function old(string $key, mixed $default = ''): mixed { return $_SESSION['_old'][$key] ?? $default; }
function set_old(array $input): void { $_SESSION['_old'] = $input; }
function clear_old(): void { unset($_SESSION['_old']); }

function slugify(string $text): string
{
    $map = ['ş'=>'s','Ş'=>'s','ı'=>'i','İ'=>'i','ç'=>'c','Ç'=>'c','ü'=>'u','Ü'=>'u','ö'=>'o','Ö'=>'o','ğ'=>'g','Ğ'=>'g'];
    $text = strtr(trim($text), $map);
    $text = mb_strtolower($text, 'UTF-8');
    $text = preg_replace('/[^a-z0-9]+/u', '-', $text) ?? '';
    return trim($text, '-') ?: 'icerik-' . bin2hex(random_bytes(3));
}

function site_default_settings(): array
{
    return [
        'site_title' => 'Nekrut Wellness & Spa',
        'brand_name' => 'Nekrut Wellness & Spa',
        'hotel_name' => 'Nekrut Hotel',
        'hotel_url' => 'https://nekruthotel.com',
        'brand_tagline' => 'A Nekrut Hotel Experience',
        'brand_description' => 'Nekrut Hotel bünyesinde İstanbul’da hizmet veren, beş yıldızlı otel standartlarında wellness, spa ve geleneksel bakım deneyimleri sunan kurumsal merkez.',
        'meta_description' => 'Nekrut Hotel bünyesindeki wellness ve spa deneyimlerini keşfedin. Hizmet, tarih ve saati seçerek İstanbul’da online rezervasyon oluşturun.',
        'address' => 'Nekrut Hotel, İstanbul, Türkiye',
        'address_locality' => 'İstanbul',
        'address_region' => 'İstanbul',
        'email' => 'wellness@nekrut.com',
        'price_range' => '₺₺₺',
        'logo_dark' => '/assets/img/logo.svg',
        'logo_light' => '/assets/img/logo-light.svg',
        'favicon' => '/assets/img/favicon.svg',
        'og_image' => '/assets/img/og-cover.png',
        'primary_color' => '#17352f',
        'accent_color' => '#b89a68',
        'surface_color' => '#f3efe7',
        'slot_step_minutes' => '30',
        'reservation_notice_hours' => '2',
        'cookie_consent_enabled' => '1',
        'reservation_auto_confirm' => '0',
        'amp_enabled' => '0',
        'amp_base_url' => 'https://nekrut.online',
        'amp_pages' => 'posts',
        'gemini_model' => 'gemini-2.5-flash-lite',
        'brand_facts' => 'Nekrut Hotel bünyesinde İstanbul’da hizmet veren beş yıldızlı otel wellness ve spa merkezi. Online rezervasyon alınır, site üzerinden ödeme veya kredi kartı bilgisi alınmaz. Hizmetler uzman yerli ve yabancı terapistler tarafından sunulur.',
        'ai_banned_claims' => 'Türkiye’nin en büyüğü; kesin tedavi; hastalık iyileştirir; garanti sonuç; doktor yerine geçer; rakipsiz; en iyi',
        'footer_text' => 'Nekrut Hotel’in beş yıldızlı hizmet anlayışıyla tasarlanan seçkin wellness ve spa deneyimi.',
    ];
}

function setting_cache_reset(): void
{
    unset($GLOBALS['NEKRUT_SETTINGS_CACHE']);
}

function setting(string $key, mixed $default = null): mixed
{
    if (!isset($GLOBALS['NEKRUT_SETTINGS_CACHE']) || !is_array($GLOBALS['NEKRUT_SETTINGS_CACHE'])) {
        $GLOBALS['NEKRUT_SETTINGS_CACHE'] = [];
        if (db_table_exists('settings')) {
            try {
                foreach (db()->query('SELECT setting_key,setting_value FROM settings')->fetchAll() as $row) {
                    $GLOBALS['NEKRUT_SETTINGS_CACHE'][(string) $row['setting_key']] = $row['setting_value'];
                }
            } catch (Throwable) {
            }
        }
    }

    $settings = $GLOBALS['NEKRUT_SETTINGS_CACHE'];
    if (!array_key_exists($key, $settings)) return $default;
    $value = $settings[$key];

    // SEO ve kurumsal kimlik alanlarında boş kayıt, çağrıda verilen güvenli varsayılanı ezmesin.
    if ($default !== null && ($value === null || (is_string($value) && trim($value) === ''))) {
        return $default;
    }
    return $value;
}

function save_setting(string $key, mixed $value, bool $encrypted = false): void
{
    $stored = $encrypted ? app_encrypt((string) $value) : (string) $value;
    $stmt = db()->prepare('INSERT INTO settings(setting_key,setting_value,is_encrypted,updated_at) VALUES(?,?,?,NOW()) ON DUPLICATE KEY UPDATE setting_value=VALUES(setting_value),is_encrypted=VALUES(is_encrypted),updated_at=NOW()');
    $stmt->execute([$key, $stored, $encrypted ? 1 : 0]);
    if (isset($GLOBALS['NEKRUT_SETTINGS_CACHE']) && is_array($GLOBALS['NEKRUT_SETTINGS_CACHE'])) {
        $GLOBALS['NEKRUT_SETTINGS_CACHE'][$key] = $stored;
    }
}

function ensure_site_default_settings(): void
{
    if (!db_table_exists('settings')) return;

    $version = '2026-07-30-corporate-seo-v1';
    $stmt = db()->prepare('SELECT setting_value FROM settings WHERE setting_key=? LIMIT 1');
    $stmt->execute(['site_defaults_version']);
    if ((string) ($stmt->fetchColumn() ?: '') === $version) return;

    $rows = [];
    foreach (db()->query('SELECT setting_key,setting_value FROM settings')->fetchAll() as $row) {
        $rows[(string) $row['setting_key']] = (string) ($row['setting_value'] ?? '');
    }

    foreach (site_default_settings() as $key => $value) {
        $current = $rows[$key] ?? '';
        if (trim($current) === '') {
            save_setting($key, $value);
            $rows[$key] = $value;
        }
    }

    // Eski demo SVG sosyal görselini sosyal platformlarla daha uyumlu 1200x630 PNG ile değiştir.
    if (($rows['og_image'] ?? '') === '/assets/img/og-cover.svg') {
        save_setting('og_image', '/assets/img/og-cover.png');
    }

    save_setting('site_defaults_version', $version);
    setting_cache_reset();
}

function amp_path_allowed(string $path): bool
{
    if (!setting_bool('amp_enabled')) return false;
    $path = '/' . ltrim($path, '/');
    if (str_starts_with($path, '/rezervasyon')) return false;

    $mode = (string) setting('amp_pages', 'posts');
    $isPost = $path === '/wellness-rehberi' || str_starts_with($path, '/makale/');
    $isService = $path === '/hizmetler' || str_starts_with($path, '/hizmet/');
    $isPage = $path === '/' || $path === '/galeri' || str_starts_with($path, '/kurumsal/');

    return match ($mode) {
        'posts' => $isPost,
        'posts_services' => $isPost || $isService,
        'all' => $isPost || $isService || $isPage,
        default => false,
    };
}

function upload_image(string $field, string $folder = 'general'): ?string
{
    if (empty($_FILES[$field]['tmp_name']) || $_FILES[$field]['error'] !== UPLOAD_ERR_OK) return null;
    $tmp = $_FILES[$field]['tmp_name'];
    $max = 8 * 1024 * 1024;
    if ($_FILES[$field]['size'] > $max) throw new RuntimeException('Görsel en fazla 8 MB olabilir.');
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime = $finfo->file($tmp);
    $allowed = ['image/jpeg'=>'jpg','image/png'=>'png','image/webp'=>'webp','image/avif'=>'avif','image/x-icon'=>'ico','image/vnd.microsoft.icon'=>'ico'];
    if (!isset($allowed[$mime])) throw new RuntimeException('Yalnız JPG, PNG, WEBP, AVIF veya ICO yüklenebilir.');
    $dir = dirname(__DIR__) . '/uploads/' . trim($folder, '/');
    if (!is_dir($dir) && !mkdir($dir, 0755, true) && !is_dir($dir)) throw new RuntimeException('Yükleme klasörü oluşturulamadı.');
    $name = bin2hex(random_bytes(16)) . '.' . $allowed[$mime];
    if (!move_uploaded_file($tmp, $dir . '/' . $name)) throw new RuntimeException('Görsel kaydedilemedi.');
    return '/uploads/' . trim($folder, '/') . '/' . $name;
}

function render(string $view, array $data = [], string $layout = 'default'): void
{
    extract($data, EXTR_SKIP);
    $viewFile = dirname(__DIR__) . '/views/' . $view . '.php';
    if (!is_file($viewFile)) throw new RuntimeException('Görünüm bulunamadı: ' . $view);
    if ($layout === 'none') { require $viewFile; return; }
    ob_start();
    require $viewFile;
    $content = ob_get_clean();
    require dirname(__DIR__) . '/views/partials/header.php';
    echo $content;
    require dirname(__DIR__) . '/views/partials/footer.php';
}

function format_date_tr(string $date): string
{
    $months = [1=>'Ocak','Şubat','Mart','Nisan','Mayıs','Haziran','Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'];
    $ts = strtotime($date);
    return date('j', $ts) . ' ' . $months[(int) date('n', $ts)] . ' ' . date('Y', $ts);
}

function json_response(array $data, int $status = 200): never
{
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    header('Cache-Control: no-store');
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function valid_iso_date(string $date): bool
{
    $parsed = DateTimeImmutable::createFromFormat('!Y-m-d', $date);
    $errors = DateTimeImmutable::getLastErrors();
    return $parsed instanceof DateTimeImmutable
        && ($errors === false || ((int)$errors['warning_count'] === 0 && (int)$errors['error_count'] === 0))
        && $parsed->format('Y-m-d') === $date;
}

function request_is_post(): bool { return ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST'; }
function setting_bool(string $key, bool $default = false): bool { return filter_var(setting($key, $default ? '1' : '0'), FILTER_VALIDATE_BOOL); }

function amp_url(string $path): ?string
{
    $path = '/' . ltrim($path, '/');
    if (!amp_path_allowed($path)) return null;
    $base = rtrim((string) setting('amp_base_url', base_url()), '/');
    if ($base === base_url()) return $base . '/amp' . ($path === '/' ? '' : $path);
    return $base . ($path === '/' ? '/' : $path);
}

function is_amp_request(): bool
{
    if (!setting_bool('amp_enabled')) return false;
    if (defined('NEKRUT_AMP')) return true;
    $ampBase = parse_url((string) setting('amp_base_url', ''), PHP_URL_HOST);
    return $ampBase && strcasecmp($ampBase, $_SERVER['HTTP_HOST'] ?? '') === 0 && $ampBase !== parse_url(base_url(), PHP_URL_HOST);
}


function sanitize_rich_html(string $html): string
{
    $html = preg_replace('~<(script|style|iframe|object|embed|form|input|button|textarea|select|link|meta)[^>]*>.*?</\1>~is', '', $html) ?? '';
    $html = preg_replace('~<(script|style|iframe|object|embed|form|input|button|textarea|select|link|meta)[^>]*/?>~is', '', $html) ?? '';
    $html = strip_tags($html, '<p><h2><h3><h4><ul><ol><li><strong><em><b><i><a><blockquote><br><hr>');
    $html = preg_replace('/\s(on\w+|style|id|class|srcdoc)\s*=\s*("[^"]*"|\'[^\']*\'|[^\s>]+)/iu', '', $html) ?? '';
    $html = preg_replace_callback('/href\s*=\s*(["\'])(.*?)\1/iu', static function(array $m): string {
        $href = trim($m[2]);
        if (preg_match('~^(javascript|data|vbscript):~i', $href)) return 'href="#"';
        return 'href=' . $m[1] . e($href) . $m[1] . ' rel="noopener"';
    }, $html) ?? '';
    return trim($html);
}

function content_excerpt(string $html, int $length = 180): string
{
    $text = trim(preg_replace('/\s+/u', ' ', strip_tags($html)) ?? '');
    return mb_strlen($text) <= $length ? $text : rtrim(mb_substr($text, 0, $length - 1)) . '…';
}
