<?php
/**
 * Slate — Settings.
 *
 * Settings are stored in the `settings` table (key/value). Each
 * card on this page has its own form and Save button so partial
 * saves are clean and the user doesn't have to scroll to find
 * what changed.
 *
 * Cards: General, Branding, Business, Email (SMTP).
 * SMTP password is encrypted via slate_encrypt_secret().
 */
require_once dirname(__DIR__) . '/config.php';
Auth::require();
Auth::requirePerm('settings.view');

$canEdit    = Auth::can('settings.edit') || Auth::isSuperAdmin();
$pageTitle  = __('settings', 'Settings');
$currentNav = 'settings';

$flash = null;

// ─── POST handler ────────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!csrf_verify()) {
        $flash = ['type' => 'error', 'msg' => __('csrf_failed', 'Security check failed.')];
    } elseif (!$canEdit) {
        $flash = ['type' => 'error', 'msg' => __('forbidden', 'You do not have permission to edit settings.')];
    } else {
        $action = $_POST['_action'] ?? '';

        if ($action === 'save_general') {
            // Defensive: strip HTML + control chars so a pasted <script> blob
            // never survives a save. Settings are plain text.
            $name = (string)($_POST['site_name'] ?? '');
            $name = preg_replace('/[\x00-\x08\x0B-\x1F\x7F]+/', '', $name) ?? '';
            $name = strip_tags($name);
            $name = trim(preg_replace('/\s+/', ' ', $name) ?? '');
            $lang = trim((string)($_POST['default_language'] ?? 'en'));
            if (!preg_match('/^[a-zA-Z_-]{2,16}$/', $lang)) $lang = 'en';
            if ($name === '') {
                $flash = ['type' => 'error', 'msg' => __('site_name_required', 'Site name is required.')];
            } else {
                Database::setSetting('site_name', mb_substr($name, 0, 120));
                Database::setSetting('default_language', preg_match('/^[a-z]{2}$/', $lang) ? $lang : 'en');
                AuditLog::record('settings.updated', 'general');
                $flash = ['type' => 'success', 'msg' => __('settings_saved', 'Settings saved.')];
            }
        }

        elseif ($action === 'save_branding') {
            $accent = trim((string)($_POST['accent_color'] ?? ''));
            if ($accent !== '' && !preg_match('/^#[0-9a-fA-F]{6}$/', $accent)) {
                $flash = ['type' => 'error', 'msg' => __('color_invalid', 'Accent color must be a hex value like #B17A3C.')];
            } else {
                Database::setSetting('brand_accent_color', $accent);

                // Logo source priority (highest wins):
                //   1. New file upload via $_FILES['logo']
                //   2. Picker-selected path in $_POST['picked_logo_path']
                //      (set by the media-library plugin's picker if active)
                //   3. Keep whatever is already saved
                //
                // The 'stored_path' key was a longstanding bug — Uploads::handle()
                // returns 'path', not 'stored_path'. So uploads succeeded on disk
                // but the DB setting got NULL. Fixed below.
                if (!empty($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
                    try {
                        $result = Uploads::handle('logo', 'branding', [
                            'allowed_mimes'  => ['image/png', 'image/jpeg', 'image/svg+xml', 'image/webp'],
                            'max_bytes'      => 2 * 1024 * 1024,
                        ]);
                        if ($result['ok']) {
                            Database::setSetting('brand_logo_path', $result['path']);
                            // Register in the media library cache if it's
                            // available, so this logo appears in the picker
                            // and Media browse page right away.
                            if (class_exists('MediaLibrary')) {
                                $info = @getimagesize(SLATE_ROOT . $result['path']);
                                MediaLibrary::register($result['path'], [
                                    'mime'          => $result['mime']     ?? '',
                                    'size_bytes'    => $result['size']     ?? 0,
                                    'width'         => is_array($info) ? ($info[0] ?? null) : null,
                                    'height'        => is_array($info) ? ($info[1] ?? null) : null,
                                    'original_name' => $result['original'] ?? '',
                                ]);
                            }
                        } else {
                            $flash = ['type' => 'error', 'msg' => $result['error'] ?? __('upload_failed', 'Upload failed.')];
                        }
                    } catch (\Throwable $e) {
                        $flash = ['type' => 'error', 'msg' => __('upload_failed', 'Logo upload failed.') . ' ' . $e->getMessage()];
                    }
                }
                // Picker-selected path (only if no upload happened above).
                elseif (!empty($_POST['picked_logo_path'])) {
                    $picked = trim((string)$_POST['picked_logo_path']);
                    if (class_exists('MediaLibrary') && MediaLibrary::isManagedPath($picked)) {
                        Database::setSetting('brand_logo_path', $picked);
                    } else {
                        $flash = ['type' => 'error', 'msg' =>
                            __('logo_path_invalid', 'Picked logo path is not in the media library.')];
                    }
                }

                if (isset($_POST['remove_logo']) && $_POST['remove_logo'] === '1') {
                    $current = Database::setting('brand_logo_path');
                    // Don't actually delete the file from disk on
                    // "remove" — just unlink it from the setting. The
                    // file stays in uploads/branding/ and can be re-
                    // picked from the media library. (If the user really
                    // wants it gone, they can delete it from Media.)
                    Database::setSetting('brand_logo_path', '');
                }

                if (!$flash) {
                    AuditLog::record('settings.updated', 'branding');
                    $flash = ['type' => 'success', 'msg' => __('settings_saved', 'Settings saved.')];
                }
            }
        }

        elseif ($action === 'save_business') {
            Database::setSetting('business_name',    mb_substr(trim((string)($_POST['business_name']    ?? '')), 0, 190));
            Database::setSetting('business_email',   mb_substr(trim((string)($_POST['business_email']   ?? '')), 0, 190));
            Database::setSetting('business_phone',   mb_substr(trim((string)($_POST['business_phone']   ?? '')), 0, 64));
            Database::setSetting('business_address', mb_substr(trim((string)($_POST['business_address'] ?? '')), 0, 500));
            Database::setSetting('business_hours',   mb_substr(trim((string)($_POST['business_hours']   ?? '')), 0, 500));
            AuditLog::record('settings.updated', 'business');
            $flash = ['type' => 'success', 'msg' => __('settings_saved', 'Settings saved.')];
        }

        elseif ($action === 'save_smtp') {
            $host = trim((string)($_POST['smtp_host'] ?? ''));
            $port = (int)($_POST['smtp_port'] ?? 0);
            $user = trim((string)($_POST['smtp_user'] ?? ''));
            $pass = (string)($_POST['smtp_pass'] ?? '');
            $enc  = (string)($_POST['smtp_encryption'] ?? 'tls');
            $fromName  = trim((string)($_POST['smtp_from_name']  ?? ''));
            $fromEmail = trim((string)($_POST['smtp_from_email'] ?? ''));

            if ($fromEmail !== '' && !filter_var($fromEmail, FILTER_VALIDATE_EMAIL)) {
                $flash = ['type' => 'error', 'msg' => __('from_email_invalid', 'From email is not a valid address.')];
            } elseif ($port !== 0 && ($port < 1 || $port > 65535)) {
                $flash = ['type' => 'error', 'msg' => __('port_invalid', 'SMTP port must be between 1 and 65535.')];
            } elseif (!in_array($enc, ['none', 'tls', 'ssl'], true)) {
                $flash = ['type' => 'error', 'msg' => __('encryption_invalid', 'Encryption must be none, tls, or ssl.')];
            } else {
                Database::setSetting('smtp_host', mb_substr($host, 0, 190));
                Database::setSetting('smtp_port', $port ?: '');
                Database::setSetting('smtp_user', mb_substr($user, 0, 190));
                Database::setSetting('smtp_encryption', $enc);
                Database::setSetting('smtp_from_name', mb_substr($fromName, 0, 120));
                Database::setSetting('smtp_from_email', mb_substr($fromEmail, 0, 190));

                // Only update password if a new one was typed
                if ($pass !== '') {
                    Database::setSetting('smtp_pass', slate_encrypt_secret($pass));
                }
                AuditLog::record('settings.updated', 'smtp');
                $flash = ['type' => 'success', 'msg' => __('settings_saved', 'Settings saved.')];
            }
        }

        elseif ($action === 'test_smtp') {
            $to = trim((string)($_POST['test_email'] ?? ''));
            if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
                $flash = ['type' => 'error', 'msg' => __('test_email_invalid', 'Enter a valid email address.')];
            } else {
                $ok = Mailer::send($to, 'Slate SMTP test',
                    "<p>This is a test message sent from your Slate install.</p>"
                  . "<p>If you received it, your SMTP settings are working.</p>");
                if ($ok) {
                    AuditLog::record('settings.smtp_test', $to);
                    $flash = ['type' => 'success', 'msg' => sprintf(__('test_sent', 'Test email sent to %s.'), $to)];
                } else {
                    $flash = ['type' => 'error', 'msg' => __('test_failed', 'Failed to send. Check your SMTP settings and the server error log.')];
                }
            }
        }
    }
}

// ─── Load current values ─────────────────────────────────────
// Hardening (Phase 0 hotfix): some installs ended up with HTML or
// control characters stored as plain settings (e.g. a Google Tag
// Manager snippet pasted into site_name). That leaks into form
// inputs and confuses browsers. Strip control chars + tags and
// clamp to a sensible length before rendering. This is display-only;
// the underlying DB value isn't touched here — run `bin/repair-settings.php`
// or the Reset card at the bottom of this page to clean it permanently.
$_safeText = static function ($v, int $max = 500): string {
    $s = is_string($v) ? $v : (string) $v;
    // Drop NULs and any other ASCII control chars except tab/newline
    $s = preg_replace('/[\x00-\x08\x0B-\x1F\x7F]+/', '', $s) ?? '';
    // Strip HTML — settings are never supposed to contain markup
    $s = strip_tags($s);
    // Normalise whitespace + trim
    $s = trim(preg_replace('/\s+/', ' ', $s) ?? '');
    return mb_substr($s, 0, $max);
};

$g = [
    'site_name'         => $_safeText(Database::setting('site_name'), 120)         ?: 'Slate',
    'default_language'  => preg_replace('/[^a-zA-Z_-]/', '', (string)(Database::setting('default_language') ?? 'en')) ?: 'en',
];
$b = [
    'accent_color'      => preg_match('/^#[0-9a-fA-F]{6}$/', (string)Database::setting('brand_accent_color'))
                            ? Database::setting('brand_accent_color') : '#B17A3C',
    'logo_path'         => $_safeText(Database::setting('brand_logo_path'), 500),
];
$biz = [
    'name'    => $_safeText(Database::setting('business_name'),    190),
    'email'   => $_safeText(Database::setting('business_email'),   190),
    'phone'   => $_safeText(Database::setting('business_phone'),    64),
    'address' => $_safeText(Database::setting('business_address'), 500),
    'hours'   => $_safeText(Database::setting('business_hours'),   500),
];
$smtp = [
    'host'       => $_safeText(Database::setting('smtp_host'),       190),
    'port'       => preg_replace('/\D+/', '', (string)Database::setting('smtp_port')),
    'user'       => $_safeText(Database::setting('smtp_user'),       190),
    'has_pass'   => (bool)Database::setting('smtp_pass'),
    'encryption' => in_array((string)Database::setting('smtp_encryption'), ['tls','ssl','none'], true)
                     ? Database::setting('smtp_encryption') : 'tls',
    'from_name'  => $_safeText(Database::setting('smtp_from_name'),  190),
    'from_email' => $_safeText(Database::setting('smtp_from_email'), 190),
];

require __DIR__ . '/partials/header.php';

// Media-library picker integration. If the plugin is installed and
// active, load its CSS/JS so the "Pick from media library" button
// near the logo upload below works. Otherwise the button isn't
// rendered and nothing else changes.
$mediaLibraryActive = class_exists('MediaLibrary')
    && class_exists('PluginLoader')
    && PluginLoader::isActive('media-library');
?>

<?php if ($mediaLibraryActive): ?>
    <link rel="stylesheet" href="<?= e(SLATE_URL) ?>/plugins/media-library/assets/css/picker.css">
    <script src="<?= e(SLATE_URL) ?>/plugins/media-library/assets/js/picker.js"></script>
<?php endif; ?>

<?php slate_breadcrumbs([
    ['label' => __('dashboard', 'Dashboard'), 'href' => SLATE_URL . '/admin/'],
    ['label' => __('settings', 'Settings')],
]); ?>

<div class="page-header">
    <div>
        <h1><?= __('settings', 'Settings') ?></h1>
        <p class="page-header-sub">
            <?= __('settings_subtitle', 'Configure how Slate looks and behaves.') ?>
        </p>
    </div>
</div>

<?php if ($flash): ?>
    <div class="alert alert-<?= e($flash['type']) ?>" role="status"><?= e($flash['msg']) ?></div>
<?php endif; ?>

<?php /* ─── General ──────────────────────────────────────── */ ?>
<div class="card">
    <div class="card-header"><h2><?= __('general', 'General') ?></h2></div>
    <form method="post">
        <?= csrf_field() ?>
        <input type="hidden" name="_action" value="save_general">

        <div class="field">
            <label class="field-label" for="site_name"><?= __('site_name', 'Site name') ?></label>
            <input type="text" id="site_name" name="site_name" required maxlength="120"
                   value="<?= e($g['site_name']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            <div class="field-hint"><?= __('site_name_hint', 'Shown in the sidebar, on the login screen, and in browser tabs.') ?></div>
        </div>

        <div class="field">
            <label class="field-label" for="default_language"><?= __('default_language', 'Default language') ?></label>
            <select id="default_language" name="default_language" <?= $canEdit ? '' : 'disabled' ?>>
                <?php foreach (I18n::supportedLanguages() as $code => $label): ?>
                    <option value="<?= e($code) ?>" <?= $code === $g['default_language'] ? 'selected' : '' ?>>
                        <?= e($label) ?>
                    </option>
                <?php endforeach; ?>
            </select>
        </div>

        <?php if ($canEdit): ?>
            <button type="submit" class="btn btn-primary"><?= __('save_changes', 'Save changes') ?></button>
        <?php endif; ?>
    </form>
</div>

<?php /* ─── Branding ─────────────────────────────────────── */ ?>
<div class="card">
    <div class="card-header"><h2><?= __('branding', 'Branding') ?></h2></div>
    <form method="post" enctype="multipart/form-data">
        <?= csrf_field() ?>
        <input type="hidden" name="_action" value="save_branding">

        <div class="field">
            <label class="field-label" for="accent_color"><?= __('accent_color', 'Accent color') ?></label>
            <div class="flex gap-2 items-center">
                <input type="color" id="accent_color" name="accent_color"
                       value="<?= e($b['accent_color']) ?>"
                       style="height:44px;width:60px;padding:4px;cursor:pointer;border-radius:var(--radius-sm)"
                       <?= $canEdit ? '' : 'disabled' ?>>
                <input type="text" name="accent_color" value="<?= e($b['accent_color']) ?>"
                       maxlength="7" pattern="^#[0-9a-fA-F]{6}$"
                       style="font-family:var(--font-mono);max-width:160px"
                       <?= $canEdit ? '' : 'disabled' ?>>
            </div>
            <div class="field-hint"><?= __('accent_color_hint', 'Hex color. Used for buttons, active nav items, and badges. Restart browser tab to see changes.') ?></div>
        </div>

        <div class="field">
            <label class="field-label" for="logo"><?= __('logo', 'Logo') ?></label>
            <?php
            // Build the displayed URL. If logo_path is empty, show a
            // hidden preview that the picker can populate. The picker
            // looks for an <img> with id="picked_logo_path-preview" and
            // updates its src after a successful pick.
            $logoPreviewUrl = $b['logo_path']
                ? SLATE_URL . '/' . ltrim($b['logo_path'], '/')
                : '';
            ?>
            <div class="mb-2" style="padding:12px;background:var(--surface-2);border-radius:var(--radius-sm);text-align:center">
                <img id="picked_logo_path-preview"
                     src="<?= e($logoPreviewUrl) ?>" alt="Current logo"
                     style="max-height:80px;max-width:240px;<?= $logoPreviewUrl === '' ? 'display:none;' : '' ?>">
            </div>
            <?php if ($b['logo_path']): ?>
                <label class="flex items-center gap-2 mb-2">
                    <input type="checkbox" name="remove_logo" value="1"
                           style="width:18px;height:18px;accent-color:var(--accent)">
                    <span><?= __('remove_current_logo', 'Remove current logo') ?></span>
                </label>
            <?php endif; ?>
            <input type="file" id="logo" name="logo" accept="image/png,image/jpeg,image/svg+xml,image/webp"
                   <?= $canEdit ? '' : 'disabled' ?>>
            <div class="field-hint"><?= __('logo_hint', 'PNG, JPEG, SVG, or WebP. Max 2 MB.') ?></div>
            <?php if ($mediaLibraryActive): ?>
                <input type="hidden" id="picked_logo_path" name="picked_logo_path" value="">
                <button type="button" class="mlp-trigger-btn"
                        data-mlp-target="picked_logo_path"
                        data-mlp-mode="single"
                        style="margin-top:8px;">
                    <?= __('pick_logo_from_library', 'Or pick from media library…') ?>
                </button>
            <?php endif; ?>
        </div>

        <?php if ($canEdit): ?>
            <button type="submit" class="btn btn-primary"><?= __('save_changes', 'Save changes') ?></button>
        <?php endif; ?>
    </form>
</div>

<?php /* ─── Business ─────────────────────────────────────── */ ?>
<div class="card">
    <div class="card-header"><h2><?= __('business_details', 'Business details') ?></h2></div>
    <form method="post">
        <?= csrf_field() ?>
        <input type="hidden" name="_action" value="save_business">

        <div class="field">
            <label class="field-label" for="business_name"><?= __('business_name', 'Business name') ?></label>
            <input type="text" id="business_name" name="business_name" maxlength="190"
                   value="<?= e($biz['name']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
        </div>

        <div class="field-row field-row-2">
            <div class="field">
                <label class="field-label" for="business_email"><?= __('business_email', 'Contact email') ?></label>
                <input type="email" id="business_email" name="business_email" maxlength="190"
                       value="<?= e($biz['email']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            </div>
            <div class="field">
                <label class="field-label" for="business_phone"><?= __('business_phone', 'Phone') ?></label>
                <input type="tel" id="business_phone" name="business_phone" maxlength="64"
                       value="<?= e($biz['phone']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            </div>
        </div>

        <div class="field">
            <label class="field-label" for="business_address"><?= __('business_address', 'Address') ?></label>
            <textarea id="business_address" name="business_address" maxlength="500"
                      rows="3" <?= $canEdit ? '' : 'disabled' ?>><?= e($biz['address']) ?></textarea>
        </div>

        <div class="field">
            <label class="field-label" for="business_hours"><?= __('business_hours', 'Business hours') ?></label>
            <textarea id="business_hours" name="business_hours" maxlength="500"
                      rows="3" placeholder="Mon–Fri 9:00–17:00&#10;Sat 10:00–14:00"
                      <?= $canEdit ? '' : 'disabled' ?>><?= e($biz['hours']) ?></textarea>
            <div class="field-hint"><?= __('hours_hint', 'Free-form text. One line per day or range.') ?></div>
        </div>

        <?php if ($canEdit): ?>
            <button type="submit" class="btn btn-primary"><?= __('save_changes', 'Save changes') ?></button>
        <?php endif; ?>
    </form>
</div>

<?php /* ─── SMTP ─────────────────────────────────────────── */ ?>
<div class="card">
    <div class="card-header"><h2><?= __('email_smtp', 'Email (SMTP)') ?></h2></div>
    <p class="text-muted text-sm mb-3">
        <?= __('smtp_intro', 'Configure outbound email. Leave the host blank to use the server\'s mail() function as a fallback.') ?>
    </p>
    <form method="post">
        <?= csrf_field() ?>
        <input type="hidden" name="_action" value="save_smtp">

        <div class="field-row field-row-2">
            <div class="field">
                <label class="field-label" for="smtp_host">SMTP <?= __('host', 'host') ?></label>
                <input type="text" id="smtp_host" name="smtp_host" maxlength="190"
                       placeholder="smtp.example.com"
                       value="<?= e($smtp['host']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            </div>
            <div class="field">
                <label class="field-label" for="smtp_port"><?= __('port', 'Port') ?></label>
                <input type="number" id="smtp_port" name="smtp_port" min="1" max="65535"
                       placeholder="587"
                       value="<?= e((string)$smtp['port']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            </div>
        </div>

        <div class="field-row field-row-2">
            <div class="field">
                <label class="field-label" for="smtp_user"><?= __('username', 'Username') ?></label>
                <input type="text" id="smtp_user" name="smtp_user" maxlength="190" autocomplete="off"
                       value="<?= e($smtp['user']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            </div>
            <div class="field">
                <label class="field-label" for="smtp_pass"><?= __('password', 'Password') ?></label>
                <input type="password" id="smtp_pass" name="smtp_pass" autocomplete="new-password"
                       placeholder="<?= $smtp['has_pass'] ? '••••••••' : '' ?>"
                       <?= $canEdit ? '' : 'disabled' ?>>
                <div class="field-hint"><?= e($smtp['has_pass']
                    ? __('pass_change_hint', 'Leave blank to keep the existing password.')
                    : __('pass_set_hint', 'Stored encrypted with the app secret.')) ?></div>
            </div>
        </div>

        <div class="field">
            <label class="field-label" for="smtp_encryption"><?= __('encryption', 'Encryption') ?></label>
            <select id="smtp_encryption" name="smtp_encryption" <?= $canEdit ? '' : 'disabled' ?>>
                <option value="tls"  <?= $smtp['encryption'] === 'tls'  ? 'selected' : '' ?>>STARTTLS</option>
                <option value="ssl"  <?= $smtp['encryption'] === 'ssl'  ? 'selected' : '' ?>>SSL/TLS</option>
                <option value="none" <?= $smtp['encryption'] === 'none' ? 'selected' : '' ?>>None (plain)</option>
            </select>
        </div>

        <div class="field-row field-row-2">
            <div class="field">
                <label class="field-label" for="smtp_from_name"><?= __('from_name', 'From name') ?></label>
                <input type="text" id="smtp_from_name" name="smtp_from_name" maxlength="120"
                       value="<?= e($smtp['from_name']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            </div>
            <div class="field">
                <label class="field-label" for="smtp_from_email"><?= __('from_email', 'From email') ?></label>
                <input type="email" id="smtp_from_email" name="smtp_from_email" maxlength="190"
                       placeholder="no-reply@example.com"
                       value="<?= e($smtp['from_email']) ?>" <?= $canEdit ? '' : 'disabled' ?>>
            </div>
        </div>

        <?php if ($canEdit): ?>
            <button type="submit" class="btn btn-primary"><?= __('save_changes', 'Save changes') ?></button>
        <?php endif; ?>
    </form>
</div>

<?php if ($canEdit && $smtp['host'] !== ''): ?>
    <div class="card">
        <div class="card-header"><h2><?= __('test_email', 'Test email') ?></h2></div>
        <p class="text-muted text-sm mb-3">
            <?= __('test_intro', 'Send a test message to verify your SMTP settings.') ?>
        </p>
        <form method="post">
            <?= csrf_field() ?>
            <input type="hidden" name="_action" value="test_smtp">
            <div class="field">
                <label class="field-label" for="test_email"><?= __('send_to', 'Send to') ?></label>
                <input type="email" id="test_email" name="test_email" required
                       value="<?= e(Auth::user()['email']) ?>">
            </div>
            <button type="submit" class="btn"><?= __('send_test', 'Send test email') ?></button>
        </form>
    </div>
<?php endif; ?>

<?php require __DIR__ . '/partials/footer.php'; ?>
