<?php
declare(strict_types=1);

/**
 * /profile/edit.php
 * Редагування профілю (все в одному):
 * - редагування полів: email, username, ПІБ, стать, дата народження
 * - додаткові: про себе, країна, місто, освіта, місце роботи
 * - приватність: "Закрити профіль" (якщо є колонка в users)
 * - зміна паролю (за бажанням)
 * - зміна аватарки/обкладинки (upload) + видалення (і фізично з сервера)
 *
 * Оновлено/оптимізовано:
 * - PRG для успішних дій (щоб не дублювало POST при F5)
 * - безпечне перейменування папки /upload/<username>/ при зміні ніка (з перевіркою успіху)
 * - не ламаємося, якщо в users немає updated_at
 * - прибрано "required" з birthdate (може бути порожньо)
 * - м’якша інтеграція з header (noindex, canonical) + profile.css інжект без дубля
 * - блок VM Coins перенесено на /profile/coins.php
 * - у правому sidebar під блоком груп додано блок ігор
 */

require_once __DIR__ . '/../includes/start.php';
require_login();

/** @var PDO|null $pdo */
/** @var array|null $me */
$pdo = (isset($pdo) && $pdo instanceof PDO) ? $pdo : db();
$me  = $me ?? current_user();

if (!function_exists('h')) {
  function h(?string $s): string { return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
}

$userId = (int)(is_array($me) ? ($me['id'] ?? 0) : 0);
if ($userId <= 0) { header('Location: /login.php'); exit; }

/* ===== helpers ===== */
if (!function_exists('vm_starts_with')) {
  function vm_starts_with(string $hay, string $needle): bool {
    if ($needle === '') return true;
    if (function_exists('str_starts_with')) return str_starts_with($hay, $needle);
    return (strlen($hay) >= strlen($needle) && substr($hay, 0, strlen($needle)) === $needle);
  }
}

if (!function_exists('db_has_column')) {
  function db_has_column(PDO $pdo, string $table, string $col): bool {
    static $cache = [];
    $k = $table . '.' . $col;
    if (array_key_exists($k, $cache)) return (bool)$cache[$k];

    try {
      $st = $pdo->prepare("
        SELECT 1
        FROM information_schema.columns
        WHERE table_schema = DATABASE()
          AND table_name = ?
          AND column_name = ?
        LIMIT 1
      ");
      $st->execute([$table, $col]);
      $cache[$k] = (bool)$st->fetchColumn();
      return (bool)$cache[$k];
    } catch (Throwable $e) {
      $cache[$k] = false;
      return false;
    }
  }
}

if (!function_exists('vm_lower')) {
  function vm_lower(string $s): string {
    $s = trim($s);
    if ($s === '') return '';
    return function_exists('mb_strtolower') ? mb_strtolower($s) : strtolower($s);
  }
}

if (!function_exists('vm_post_csrf_value')) {
  function vm_post_csrf_value(): string {
    $t = (string)($_POST['csrf'] ?? '');
    if ($t === '') $t = (string)($_POST['csrf_token'] ?? '');
    if ($t === '') $t = (string)($_POST['_csrf'] ?? '');
    return trim($t);
  }
}

if (!function_exists('vm_csrf_ok')) {
  function vm_csrf_ok(string $token): bool {
    if (function_exists('csrf_check')) {
      try { return (bool)csrf_check($token); } catch (Throwable $e) { /* fallback below */ }
    }
    if (session_status() !== PHP_SESSION_ACTIVE) @session_start();
    $sess = (string)($_SESSION['_csrf'] ?? ($_SESSION['csrf_token'] ?? ''));
    if ($sess === '' || $token === '') return false;
    return function_exists('hash_equals') ? hash_equals($sess, $token) : ($sess === $token);
  }
}

if (!function_exists('vm_redirect')) {
  function vm_redirect(string $to): void {
    if (function_exists('redirect')) {
      redirect($to);
      return;
    }
    $code = (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') ? 303 : 302;
    header('Location: ' . $to, true, $code);
    exit;
  }
}

/* ===== columns (new + fallbacks) ===== */
$hasFullName    = db_has_column($pdo, 'users', 'full_name');
$hasGender      = db_has_column($pdo, 'users', 'gender');

$hasBirthdate   = db_has_column($pdo, 'users', 'birthdate');
$hasBirthDate   = db_has_column($pdo, 'users', 'birth_date');

$hasCountry     = db_has_column($pdo, 'users', 'country');
$hasEducation   = db_has_column($pdo, 'users', 'education');
$hasWorkplace   = db_has_column($pdo, 'users', 'workplace');
$hasWork        = db_has_column($pdo, 'users', 'work');

$hasAvatarCol   = db_has_column($pdo, 'users', 'avatar_path');
$hasCoverCol    = db_has_column($pdo, 'users', 'cover_path');
$hasPassCol     = db_has_column($pdo, 'users', 'pass_hash');
$hasUpdatedAt   = db_has_column($pdo, 'users', 'updated_at');

$birthCol = $hasBirthdate ? 'birthdate' : ($hasBirthDate ? 'birth_date' : '');
$workCol  = $hasWorkplace ? 'workplace' : ($hasWork ? 'work' : '');

/* ===== privacy column (support candidates) ===== */
$privacyCol = '';
$privacyCandidates = [
  'is_private',
  'private_profile',
  'profile_private',
  'closed_profile',
  'is_closed',
  'is_profile_private',
  'private',
];
foreach ($privacyCandidates as $c) {
  if (db_has_column($pdo, 'users', $c)) { $privacyCol = $c; break; }
}
$hasPrivacy = ($privacyCol !== '');

/* ===== load fresh user ===== */
$cols = ['id','email','username','lang','role','about','city'];
if ($hasAvatarCol) $cols[] = 'avatar_path';
if ($hasCoverCol)  $cols[] = 'cover_path';
if ($hasPassCol)   $cols[] = 'pass_hash';

if ($hasFullName) $cols[] = 'full_name';
else { $cols[] = 'first_name'; $cols[] = 'last_name'; }

if ($hasGender) $cols[] = 'gender';
if ($birthCol !== '') $cols[] = $birthCol;
if ($hasCountry) $cols[] = 'country';
if ($hasEducation) $cols[] = 'education';
if ($workCol !== '') $cols[] = $workCol;
if ($hasPrivacy) $cols[] = $privacyCol;

$st = $pdo->prepare("SELECT " . implode(',', array_unique($cols)) . " FROM users WHERE id=? LIMIT 1");
$st->execute([$userId]);
$u = $st->fetch(PDO::FETCH_ASSOC) ?: null;
if (!$u) { header('Location: /'); exit; }

/* ===== Lang ===== */
$lang = function_exists('lang') ? (string)lang() : (string)($_SESSION['lang'] ?? ($u['lang'] ?? 'uk'));
if (!in_array($lang, ['uk','ru','en'], true)) $lang = 'uk';
$T = function(string $uk, string $ru, string $en) use ($lang): string {
  if ($lang === 'ru') return $ru;
  if ($lang === 'en') return $en;
  return $uk;
};

$title = $T('Редагування профілю', 'Редактирование профиля', 'Edit profile');

/* ===== SEO ===== */
$seo_noindex = true;
$meta_robots = 'noindex, nofollow, noarchive, nosnippet';
$meta_desc   = '';
$canonicalPath = '/profile/edit.php';
$canonical = function_exists('abs_url') ? abs_url($canonicalPath) : $canonicalPath;
if (!headers_sent()) {
  header('X-Robots-Tag: ' . $meta_robots, true);
  header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0', true);
  header('Pragma: no-cache', true);
  header('Expires: 0', true);
}

/* ===== state ===== */
$okMsg  = '';
$errMsg = '';

if (function_exists('flash_get')) {
  $okMsg = (string)(flash_get('ok') ?? '');
  $errMsg = (string)(flash_get('err') ?? flash_get('error') ?? '');
}

/* ===== current values ===== */
$email = (string)($u['email'] ?? '');
$uname = (string)($u['username'] ?? '');

$username = $uname;
$safeUser = preg_replace('~[^a-zA-Z0-9_\-]+~', '_', $username) ?: ('user_' . $userId);

$fullInput = '';
if ($hasFullName) {
  $fullInput = trim((string)($u['full_name'] ?? ''));
} else {
  $fullInput = trim((string)($u['first_name'] ?? '') . ' ' . (string)($u['last_name'] ?? ''));
  $fullInput = trim(preg_replace('~\s+~u', ' ', $fullInput) ?? '');
}

$gender = $hasGender ? (string)($u['gender'] ?? '') : '';
$birth  = ($birthCol !== '' && isset($u[$birthCol])) ? (string)($u[$birthCol] ?? '') : '';

$about  = (string)($u['about'] ?? '');
$city   = (string)($u['city'] ?? '');

$country   = $hasCountry ? (string)($u['country'] ?? '') : '';
$education = $hasEducation ? (string)($u['education'] ?? '') : '';
$workplace = ($workCol !== '' && isset($u[$workCol])) ? (string)($u[$workCol] ?? '') : '';

$avatarPath = $hasAvatarCol ? trim((string)($u['avatar_path'] ?? '')) : '';
$coverPath  = $hasCoverCol  ? trim((string)($u['cover_path'] ?? ''))  : '';

$isPrivate = false;
if ($hasPrivacy && $privacyCol !== '') {
  $isPrivate = ((int)($u[$privacyCol] ?? 0) === 1);
}

$profileHref = '/profile/';
if ($username !== '') $profileHref = '/profile/?u=' . rawurlencode($username);

/* ===== filesystem ===== */
function upload_base_dir(): string {
  $base = realpath(__DIR__ . '/../upload');
  if ($base && is_dir($base)) return $base;

  $base = __DIR__ . '/../upload';
  if (!is_dir($base)) @mkdir($base, 0775, true);
  return $base;
}

function web_to_fs_path(string $webPath): string {
  return __DIR__ . '/..' . $webPath;
}

function delete_web_file(string $webPath, string $safeUser, string $type): void {
  $webPath = trim($webPath);
  if ($webPath === '') return;

  if (preg_match('~^https?://~i', $webPath)) {
    $p = parse_url($webPath);
    $webPath = (string)($p['path'] ?? '');
  }

  $needle = '/upload/' . $safeUser . '/' . $type . '/';
  if (!vm_starts_with($webPath, '/upload/')) return;
  if (strpos($webPath, $needle) === false) return;
  if (preg_match('~[\x00-\x1F\x7F]~', $webPath)) return;
  if (preg_match('~(^|/)\.\.(/|$)~', $webPath)) return;

  $fs = web_to_fs_path($webPath);
  $abs = realpath($fs);
  if ($abs === false) return;

  $uploadRoot = realpath(__DIR__ . '/../upload');
  if ($uploadRoot === false) return;

  $uploadRoot = rtrim($uploadRoot, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
  $absNorm = rtrim($abs, DIRECTORY_SEPARATOR);

  if (strpos($absNorm, rtrim($uploadRoot, DIRECTORY_SEPARATOR)) !== 0) return;

  if (is_file($absNorm)) @unlink($absNorm);
}

function move_dir_recursive(string $src, string $dst): bool {
  if (!is_dir($src)) return true;

  $dstParent = dirname($dst);
  if (!is_dir($dstParent)) @mkdir($dstParent, 0775, true);

  if (!is_dir($dst) && @rename($src, $dst)) return true;

  try {
    if (!is_dir($dst)) @mkdir($dst, 0775, true);

    $srcIt = new RecursiveIteratorIterator(
      new RecursiveDirectoryIterator($src, FilesystemIterator::SKIP_DOTS),
      RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($srcIt as $item) {
      $target = $dst . DIRECTORY_SEPARATOR . $srcIt->getSubPathName();
      if ($item->isDir()) {
        if (!is_dir($target)) @mkdir($target, 0775, true);
      } else {
        if (!is_dir(dirname($target))) @mkdir(dirname($target), 0775, true);
        @copy((string)$item, $target);
      }
    }

    $delIt = new RecursiveIteratorIterator(
      new RecursiveDirectoryIterator($src, FilesystemIterator::SKIP_DOTS),
      RecursiveIteratorIterator::CHILD_FIRST
    );

    foreach ($delIt as $item) {
      if ($item->isDir()) @rmdir((string)$item);
      else @unlink((string)$item);
    }
    @rmdir($src);

    return is_dir($dst);
  } catch (Throwable $e) {
    return false;
  }
}

/* ===== image upload ===== */
function handle_image_upload(
  PDO $pdo,
  int $userId,
  string $safeUser,
  string $type,
  int $maxBytes,
  bool $hasCol,
  string &$okMsg,
  string &$errMsg,
  callable $T
): void {
  if (!$hasCol) {
    $errMsg = $T('Колонка в БД відсутня.', 'Колонка в БД отсутствует.', 'DB column missing.');
    return;
  }

  if (!isset($_FILES['file']) || !is_uploaded_file($_FILES['file']['tmp_name'] ?? '')) {
    $errMsg = $T('Файл не вибрано.', 'Файл не выбран.', 'No file selected.');
    return;
  }

  $f = $_FILES['file'];
  $size = (int)($f['size'] ?? 0);
  if ($size <= 0) { $errMsg = $T('Порожній файл.', 'Пустой файл.', 'Empty file.'); return; }
  if ($size > $maxBytes) { $errMsg = $T('Файл завеликий.', 'Файл слишком большой.', 'File is too large.'); return; }

  $tmp = (string)($f['tmp_name'] ?? '');
  $fi = new finfo(FILEINFO_MIME_TYPE);
  $mime = (string)$fi->file($tmp);

  $allowed = [
    'image/jpeg' => 'jpg',
    'image/png'  => 'png',
    'image/webp' => 'webp',
    'image/gif'  => 'gif',
  ];
  if (!isset($allowed[$mime])) { $errMsg = $T('Непідтримуваний тип файлу.', 'Неподдерживаемый тип файла.', 'Unsupported file type.'); return; }
  $ext = $allowed[$mime];

  $baseDir = upload_base_dir();
  $dir = $baseDir . '/' . $safeUser . '/' . $type;
  if (!is_dir($dir) && !mkdir($dir, 0775, true)) {
    $errMsg = $T('Не вдалося створити каталог.', 'Не удалось создать каталог.', 'Failed to create directory.');
    return;
  }

  $name = date('Ymd_His') . '_' . bin2hex(random_bytes(6)) . '.' . $ext;
  $destFs = $dir . '/' . $name;

  if (!move_uploaded_file($tmp, $destFs)) {
    $errMsg = $T('Не вдалося зберегти файл.', 'Не удалось сохранить файл.', 'Failed to save file.');
    return;
  }

  $destWeb = '/upload/' . $safeUser . '/' . $type . '/' . $name;
  $col = ($type === 'avatar') ? 'avatar_path' : 'cover_path';

  $st = $pdo->prepare("SELECT {$col} FROM users WHERE id=? LIMIT 1");
  $st->execute([$userId]);
  $old = (string)($st->fetchColumn() ?: '');

  $st = $pdo->prepare("UPDATE users SET {$col}=? WHERE id=? LIMIT 1");
  $st->execute([$destWeb, $userId]);

  if ($old !== '') delete_web_file($old, $safeUser, $type);

  $okMsg = ($type === 'avatar')
    ? $T('Аватарку оновлено!', 'Аватар обновлён!', 'Avatar updated!')
    : $T('Обкладинку оновлено!', 'Обложка обновлена!', 'Cover updated!');
}

/* ===== POST actions ===== */
$selfUrl = '/profile/edit.php';

if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
  $action = (string)($_POST['action'] ?? 'save_profile');
  $csrf = vm_post_csrf_value();

  if (!vm_csrf_ok($csrf)) {
    $errMsg = $T(
      'Помилка безпеки (CSRF). Онови сторінку і спробуй ще раз.',
      'Ошибка безопасности (CSRF). Обнови страницу и попробуй снова.',
      'Security error (CSRF). Refresh and try again.'
    );
  } else {
    try {
      if ($action === 'save_profile') {
        $newEmail = vm_lower((string)($_POST['email'] ?? ''));
        $newUser  = trim((string)($_POST['username'] ?? ''));
        $newFull  = trim((string)($_POST['full_name'] ?? ''));
        $newFull  = trim(preg_replace('~\s+~u', ' ', $newFull) ?? '');

        $newGender = trim((string)($_POST['gender'] ?? ''));
        $newBirth  = trim((string)($_POST['birthdate'] ?? ''));
        $newAbout  = trim((string)($_POST['about'] ?? ''));
        $newCity   = trim((string)($_POST['city'] ?? ''));

        $newCountry   = trim((string)($_POST['country'] ?? ''));
        $newEducation = trim((string)($_POST['education'] ?? ''));
        $newWorkplace = trim((string)($_POST['workplace'] ?? ''));

        $newIsPrivate = $hasPrivacy ? (((int)($_POST['is_private'] ?? 0) === 1) ? 1 : 0) : 0;

        $curPass = (string)($_POST['current_password'] ?? '');
        $p1 = (string)($_POST['new_password'] ?? '');
        $p2 = (string)($_POST['new_password2'] ?? '');

        if ($newEmail === '' || !filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
          $errMsg = $T('Невірний email.', 'Неверный email.', 'Invalid email.');
        } elseif ($newUser === '' || !preg_match('~^[a-zA-Z0-9_\-]{3,32}$~', $newUser)) {
          $errMsg = $T(
            'Невірний нікнейм (3-32 символи: латиниця/цифри/_/-).',
            'Неверный никнейм (3-32 символа: латиница/цифры/_/-).',
            'Invalid username (3-32: latin/digits/_/-).'
          );
        } elseif ($newFull === '') {
          $errMsg = $T('ПІБ обовʼязкове.', 'ФИО обязательно.', 'Full name is required.');
        } elseif ($hasGender && !in_array($newGender, ['f','m'], true)) {
          $errMsg = $T('Оберіть стать.', 'Выберите пол.', 'Choose gender.');
        } elseif ($newBirth !== '' && !preg_match('~^\d{4}-\d{2}-\d{2}$~', $newBirth)) {
          $errMsg = $T('Невірна дата народження.', 'Неверная дата рождения.', 'Invalid birth date.');
        } else {
          if (vm_lower((string)($u['email'] ?? '')) !== $newEmail) {
            $st = $pdo->prepare("SELECT id FROM users WHERE email=? AND id<>? LIMIT 1");
            $st->execute([$newEmail, $userId]);
            if ($st->fetchColumn()) {
              $errMsg = $T('Цей email вже зайнятий.', 'Этот email уже занят.', 'Email is already taken.');
            }
          }

          if ($errMsg === '' && (string)($u['username'] ?? '') !== $newUser) {
            $st = $pdo->prepare("SELECT id FROM users WHERE username=? AND id<>? LIMIT 1");
            $st->execute([$newUser, $userId]);
            if ($st->fetchColumn()) {
              $errMsg = $T('Цей нікнейм вже зайнятий.', 'Этот никнейм уже занят.', 'Username is already taken.');
            }
          }

          if ($errMsg === '' && ($p1 !== '' || $p2 !== '' || $curPass !== '')) {
            if (!$hasPassCol) {
              $errMsg = $T('Немає поля паролю в БД.', 'Нет поля пароля в БД.', 'Password column missing.');
            } elseif ($curPass === '') {
              $errMsg = $T('Вкажіть поточний пароль.', 'Укажите текущий пароль.', 'Enter current password.');
            } else {
              $hash = (string)($u['pass_hash'] ?? '');
              if ($hash === '' || !password_verify($curPass, $hash)) {
                $errMsg = $T('Поточний пароль невірний.', 'Текущий пароль неверный.', 'Current password is wrong.');
              } elseif (mb_strlen($p1) < 6) {
                $errMsg = $T('Новий пароль закороткий (мін. 6).', 'Новый пароль слишком короткий (мин 6).', 'New password is too short (min 6).');
              } elseif ($p1 !== $p2) {
                $errMsg = $T('Паролі не співпадають.', 'Пароли не совпадают.', 'Passwords do not match.');
              }
            }
          }

          if ($errMsg === '') {
            $oldUsername = (string)($u['username'] ?? '');
            $oldSafe = preg_replace('~[^a-zA-Z0-9_\-]+~', '_', $oldUsername) ?: ('user_' . $userId);
            $newSafe = preg_replace('~[^a-zA-Z0-9_\-]+~', '_', $newUser) ?: ('user_' . $userId);

            $avatarNew = $hasAvatarCol ? (string)($u['avatar_path'] ?? '') : '';
            $coverNew  = $hasCoverCol  ? (string)($u['cover_path'] ?? '')  : '';

            if ($oldUsername !== $newUser && $oldSafe !== $newSafe) {
              $base = upload_base_dir();
              $src = $base . '/' . $oldSafe;
              $dst = $base . '/' . $newSafe;

              if (is_dir($src)) {
                $moved = move_dir_recursive($src, $dst);
                if (!$moved) {
                  $errMsg = $T(
                    'Не вдалося перенести папку завантажень користувача. Спробуйте пізніше.',
                    'Не удалось перенести папку загрузок пользователя. Попробуйте позже.',
                    'Failed to move user uploads folder. Try again later.'
                  );
                } else {
                  $oldPrefix = '/upload/' . $oldSafe . '/';
                  $newPrefix = '/upload/' . $newSafe . '/';

                  if ($hasAvatarCol && $avatarNew !== '' && vm_starts_with($avatarNew, $oldPrefix)) {
                    $avatarNew = $newPrefix . substr($avatarNew, strlen($oldPrefix));
                  }
                  if ($hasCoverCol && $coverNew !== '' && vm_starts_with($coverNew, $oldPrefix)) {
                    $coverNew = $newPrefix . substr($coverNew, strlen($oldPrefix));
                  }

                  $safeUser = $newSafe;
                }
              } else {
                $safeUser = $newSafe;
              }
            }

            if ($errMsg === '') {
              $sets = ['email=?','username=?','about=?','city=?'];
              $params = [
                $newEmail,
                $newUser,
                ($newAbout !== '' ? $newAbout : null),
                ($newCity !== '' ? $newCity : null),
              ];

              if ($hasUpdatedAt) {
                $sets[] = 'updated_at=NOW()';
              }

              if ($hasFullName) {
                $sets[] = 'full_name=?';
                $params[] = ($newFull !== '' ? $newFull : null);
              } else {
                $parts = preg_split('~\s+~u', $newFull, -1, PREG_SPLIT_NO_EMPTY) ?: [];
                $fn = '';
                $ln = '';
                if ($parts) { $fn = (string)array_shift($parts); $ln = trim(implode(' ', $parts)); }
                $sets[] = 'first_name=?';
                $sets[] = 'last_name=?';
                $params[] = ($fn !== '' ? $fn : null);
                $params[] = ($ln !== '' ? $ln : null);
              }

              if ($hasGender) {
                $sets[] = 'gender=?';
                $params[] = ($newGender !== '' ? $newGender : null);
              }

              if ($birthCol !== '') {
                $sets[] = $birthCol . '=?';
                $params[] = ($newBirth !== '' ? $newBirth : null);
              }

              if ($hasCountry) {
                $sets[] = 'country=?';
                $params[] = ($newCountry !== '' ? $newCountry : null);
              }

              if ($hasEducation) {
                $sets[] = 'education=?';
                $params[] = ($newEducation !== '' ? $newEducation : null);
              }

              if ($workCol !== '') {
                $sets[] = $workCol . '=?';
                $params[] = ($newWorkplace !== '' ? $newWorkplace : null);
              }

              if ($hasPrivacy && $privacyCol !== '') {
                $sets[] = $privacyCol . '=?';
                $params[] = $newIsPrivate;
              }

              if ($hasAvatarCol && $avatarNew !== '') {
                $sets[] = 'avatar_path=?';
                $params[] = $avatarNew;
              }

              if ($hasCoverCol && $coverNew !== '') {
                $sets[] = 'cover_path=?';
                $params[] = $coverNew;
              }

              if ($hasPassCol && $p1 !== '' && $p1 === $p2 && $curPass !== '') {
                $newHash = password_hash($p1, PASSWORD_DEFAULT);
                $sets[] = 'pass_hash=?';
                $params[] = $newHash;
              }

              $params[] = $userId;

              $sql = "UPDATE users SET " . implode(', ', $sets) . " WHERE id=? LIMIT 1";
              $st = $pdo->prepare($sql);
              $st->execute($params);

              if (isset($_SESSION['user']) && is_array($_SESSION['user'])) {
                $_SESSION['user']['email'] = $newEmail;
                $_SESSION['user']['username'] = $newUser;
                if ($hasFullName) $_SESSION['user']['full_name'] = $newFull;
                else {
                  $_SESSION['user']['first_name'] = $fn ?? '';
                  $_SESSION['user']['last_name']  = $ln ?? '';
                }
                if ($hasAvatarCol) $_SESSION['user']['avatar_path'] = $avatarNew ?: ($_SESSION['user']['avatar_path'] ?? null);
                if ($hasCoverCol)  $_SESSION['user']['cover_path']  = $coverNew  ?: ($_SESSION['user']['cover_path'] ?? null);
              }

              $okMsg = $T('Збережено!', 'Сохранено!', 'Saved!');
            }
          }
        }

        if ($okMsg !== '' && $errMsg === '') {
          if (function_exists('flash_set')) flash_set('ok', $okMsg);
          vm_redirect($selfUrl);
        }
      }
      elseif ($action === 'upload_avatar') {
        handle_image_upload($pdo, $userId, $safeUser, 'avatar', 10 * 1024 * 1024, $hasAvatarCol, $okMsg, $errMsg, $T);
        if ($okMsg !== '' && $errMsg === '') {
          if (function_exists('flash_set')) flash_set('ok', $okMsg);
          vm_redirect($selfUrl);
        }
      }
      elseif ($action === 'upload_cover') {
        handle_image_upload($pdo, $userId, $safeUser, 'cover', 12 * 1024 * 1024, $hasCoverCol, $okMsg, $errMsg, $T);
        if ($okMsg !== '' && $errMsg === '') {
          if (function_exists('flash_set')) flash_set('ok', $okMsg);
          vm_redirect($selfUrl);
        }
      }
      elseif ($action === 'delete_avatar') {
        if (!$hasAvatarCol) {
          $errMsg = $T('Колонка в БД відсутня.', 'Колонка в БД отсутствует.', 'DB column missing.');
        } else {
          $st = $pdo->prepare("SELECT avatar_path, username FROM users WHERE id=? LIMIT 1");
          $st->execute([$userId]);
          $row = $st->fetch(PDO::FETCH_ASSOC) ?: [];
          $old = trim((string)($row['avatar_path'] ?? ''));
          $curU = (string)($row['username'] ?? $uname);
          $curSafe = preg_replace('~[^a-zA-Z0-9_\-]+~', '_', $curU) ?: ('user_' . $userId);

          if ($old !== '') delete_web_file($old, $curSafe, 'avatar');

          $st = $pdo->prepare("UPDATE users SET avatar_path=NULL WHERE id=? LIMIT 1");
          $st->execute([$userId]);

          $okMsg = $T('Аватарку видалено.', 'Аватар удалён.', 'Avatar removed.');
          if (function_exists('flash_set')) flash_set('ok', $okMsg);
          vm_redirect($selfUrl);
        }
      }
      elseif ($action === 'delete_cover') {
        if (!$hasCoverCol) {
          $errMsg = $T('Колонка в БД відсутня.', 'Колонка в БД отсутствует.', 'DB column missing.');
        } else {
          $st = $pdo->prepare("SELECT cover_path, username FROM users WHERE id=? LIMIT 1");
          $st->execute([$userId]);
          $row = $st->fetch(PDO::FETCH_ASSOC) ?: [];
          $old = trim((string)($row['cover_path'] ?? ''));
          $curU = (string)($row['username'] ?? $uname);
          $curSafe = preg_replace('~[^a-zA-Z0-9_\-]+~', '_', $curU) ?: ('user_' . $userId);

          if ($old !== '') delete_web_file($old, $curSafe, 'cover');

          $st = $pdo->prepare("UPDATE users SET cover_path=NULL WHERE id=? LIMIT 1");
          $st->execute([$userId]);

          $okMsg = $T('Обкладинку видалено.', 'Обложка удалена.', 'Cover removed.');
          if (function_exists('flash_set')) flash_set('ok', $okMsg);
          vm_redirect($selfUrl);
        }
      }
      else {
        $errMsg = $T('Невідома дія.', 'Неизвестное действие.', 'Unknown action.');
      }

      $st = $pdo->prepare("SELECT " . implode(',', array_unique($cols)) . " FROM users WHERE id=? LIMIT 1");
      $st->execute([$userId]);
      $u2 = $st->fetch(PDO::FETCH_ASSOC) ?: null;
      if ($u2) {
        $u = $u2;

        $email = (string)($u['email'] ?? '');
        $uname = (string)($u['username'] ?? '');
        $username = $uname;
        $safeUser = preg_replace('~[^a-zA-Z0-9_\-]+~', '_', $username) ?: ('user_' . $userId);

        $avatarPath = $hasAvatarCol ? trim((string)($u['avatar_path'] ?? '')) : '';
        $coverPath  = $hasCoverCol  ? trim((string)($u['cover_path'] ?? ''))  : '';

        if ($hasFullName) {
          $fullInput = trim((string)($u['full_name'] ?? ''));
        } else {
          $fullInput = trim((string)($u['first_name'] ?? '') . ' ' . (string)($u['last_name'] ?? ''));
          $fullInput = trim(preg_replace('~\s+~u', ' ', $fullInput) ?? '');
        }

        $gender = $hasGender ? (string)($u['gender'] ?? '') : '';
        $birth  = ($birthCol !== '' && isset($u[$birthCol])) ? (string)($u[$birthCol] ?? '') : '';

        $about  = (string)($u['about'] ?? '');
        $city   = (string)($u['city'] ?? '');

        $country   = $hasCountry ? (string)($u['country'] ?? '') : '';
        $education = $hasEducation ? (string)($u['education'] ?? '') : '';
        $workplace = ($workCol !== '' && isset($u[$workCol])) ? (string)($u[$workCol] ?? '') : '';

        if ($hasPrivacy && $privacyCol !== '') $isPrivate = ((int)($u[$privacyCol] ?? 0) === 1);
        else $isPrivate = false;

        $profileHref = '/profile/';
        if ($username !== '') $profileHref = '/profile/?u=' . rawurlencode($username);
      }

    } catch (Throwable $e) {
      $errMsg = $T('Помилка. Перевір дані.', 'Ошибка. Проверь данные.', 'Error. Please check data.');
    }
  }
}

/* ===== Header + profile.css ===== */
$headerPath = __DIR__ . '/../includes/header.php';
ob_start();
require $headerPath;
$hdr = (string)ob_get_clean();

$cssHref = '/css/profile.css?v=4';
if (stripos($hdr, $cssHref) === false && strpos($hdr, '</head>') !== false) {
  $hdr = str_replace('</head>', "  <link rel=\"stylesheet\" href=\"" . h($cssHref) . "\">\n</head>", $hdr);
}
echo $hdr;

$csrfField = function_exists('csrf_field')
  ? (string)csrf_field()
  : '<input type="hidden" name="csrf" value="'.h((string)($_SESSION['_csrf'] ?? ($_SESSION['csrf_token'] ?? ''))).'">';

?>
<div class="feed-layout">
  <aside>
    <div class="sidebar-sticky">
      <?php require __DIR__ . '/../blocks/profile.php'; ?>
    </div>
  </aside>

  <section>
    <div class="card card-app p-3 mb-3">
      <div class="d-flex align-items-center justify-content-between gap-2">
        <div class="fw-semibold fs-5"><?= h($title) ?></div>
        <div class="d-flex gap-2 flex-wrap">
          <a class="btn btn-sm btn-outline-primary" href="/profile/coins.php">VM Coins</a>
          <a class="btn btn-sm btn-outline-secondary" href="<?= h($profileHref) ?>"><?= h($T('Назад','Назад','Back')) ?></a>
        </div>
      </div>

      <?php if ($okMsg !== ''): ?>
        <div class="alert alert-success mt-3 mb-0"><?= h($okMsg) ?></div>
      <?php elseif ($errMsg !== ''): ?>
        <div class="alert alert-danger mt-3 mb-0"><?= h($errMsg) ?></div>
      <?php endif; ?>
    </div>

    <!-- AVATAR -->
    <div class="card card-app p-3 mb-3">
      <div class="fw-semibold fs-6 mb-2"><?= h($T('Аватарка','Аватар','Avatar')) ?></div>

      <div class="d-flex align-items-center gap-3 flex-wrap">
        <div style="width:96px;height:96px;border-radius:18px;overflow:hidden;background:#f1f3f5;border:1px solid rgba(0,0,0,.08);display:flex;align-items:center;justify-content:center;">
          <?php if ($avatarPath !== ''): ?>
            <img src="<?= h($avatarPath) ?>" alt="" style="width:100%;height:100%;object-fit:cover;">
          <?php else: ?>
            <div style="font-size:28px;opacity:.55;">👤</div>
          <?php endif; ?>
        </div>

        <div class="flex-grow-1" style="min-width:260px;">
          <form method="post" enctype="multipart/form-data" class="d-flex gap-2 align-items-end flex-wrap">
            <?= $csrfField ?>
            <input type="hidden" name="action" value="upload_avatar">
            <div class="flex-grow-1" style="min-width:240px;">
              <label class="form-label mb-1"><?= h($T('Завантажити нову аватарку (до 10MB)','Загрузить новый аватар (до 10MB)','Upload new avatar (up to 10MB)')) ?></label>
              <input class="form-control" type="file" name="file" accept="image/*" <?= $hasAvatarCol ? 'required' : 'disabled' ?>>
            </div>
            <button class="btn btn-primary" type="submit" <?= $hasAvatarCol ? '' : 'disabled' ?>><?= h($T('Завантажити','Загрузить','Upload')) ?></button>
          </form>

          <?php if ($avatarPath !== ''): ?>
            <form method="post" class="mt-2" onsubmit="return confirm('<?= h($T('Видалити аватарку?','Удалить аватар?','Delete avatar?')) ?>');">
              <?= $csrfField ?>
              <input type="hidden" name="action" value="delete_avatar">
              <button class="btn btn-outline-danger btn-sm" type="submit"><?= h($T('Видалити аватарку','Удалить аватар','Delete avatar')) ?></button>
            </form>
          <?php endif; ?>
        </div>
      </div>
    </div>

    <!-- COVER -->
    <div class="card card-app p-3 mb-3">
      <div class="fw-semibold fs-6 mb-2"><?= h($T('Обкладинка','Обложка','Cover')) ?></div>

      <div style="border-radius:16px;overflow:hidden;background:#f1f3f5;border:1px solid rgba(0,0,0,.08);">
        <?php if ($coverPath !== ''): ?>
          <img src="<?= h($coverPath) ?>" alt="" style="width:100%;height:220px;object-fit:cover;display:block;">
        <?php else: ?>
          <div style="height:220px;display:flex;align-items:center;justify-content:center;opacity:.55;">
            <div style="font-size:28px;">🖼️</div>
          </div>
        <?php endif; ?>
      </div>

      <form method="post" enctype="multipart/form-data" class="mt-3 d-flex gap-2 align-items-end flex-wrap">
        <?= $csrfField ?>
        <input type="hidden" name="action" value="upload_cover">
        <div class="flex-grow-1" style="min-width:240px;">
          <label class="form-label mb-1"><?= h($T('Завантажити нову обкладинку (до 12MB)','Загрузить новую обложку (до 12MB)','Upload new cover (up to 12MB)')) ?></label>
          <input class="form-control" type="file" name="file" accept="image/*" <?= $hasCoverCol ? 'required' : 'disabled' ?>>
        </div>
        <button class="btn btn-primary" type="submit" <?= $hasCoverCol ? '' : 'disabled' ?>><?= h($T('Завантажити','Загрузить','Upload')) ?></button>
      </form>

      <?php if ($coverPath !== ''): ?>
        <form method="post" class="mt-2" onsubmit="return confirm('<?= h($T('Видалити обкладинку?','Удалить обложку?','Delete cover?')) ?>');">
          <?= $csrfField ?>
          <input type="hidden" name="action" value="delete_cover">
          <button class="btn btn-outline-danger btn-sm" type="submit"><?= h($T('Видалити обкладинку','Удалить обложку','Delete cover')) ?></button>
        </form>
      <?php endif; ?>
    </div>

    <!-- PROFILE INFO -->
    <div class="card card-app p-3 mb-3">
      <div class="fw-semibold fs-6 mb-2"><?= h($T('Дані профілю','Данные профиля','Profile info')) ?></div>

      <form method="post" class="mt-2" autocomplete="off">
        <?= $csrfField ?>
        <input type="hidden" name="action" value="save_profile">

        <?php if ($hasPrivacy): ?>
          <div class="mb-3">
            <label class="form-label d-flex align-items-center gap-2" style="cursor:pointer;">
              <input type="checkbox" name="is_private" value="1" <?= $isPrivate ? 'checked' : '' ?>>
              <span class="fw-semibold"><?= h($T('Закрити профіль','Закрыть профиль','Close profile')) ?></span>
            </label>
            <div class="form-text">
              <?= h($T(
                'Якщо увімкнено — гості будуть перекинуті на авторизацію, а авторизованим показуватиметься лише мінімум (ПІБ, нік, кнопка дружби).',
                'Если включено — гостей перебросит на авторизацию, а авторизованным покажется только минимум (ФИО, ник, кнопка дружбы).',
                'If enabled — guests are redirected to login and logged-in users see only minimal info (name, username, friend button).'
              )) ?>
            </div>
          </div>
        <?php endif; ?>

        <div class="mb-3">
          <label class="form-label"><?= h($T('Email','Email','Email')) ?></label>
          <input class="form-control" type="email" name="email" value="<?= h($email) ?>" required>
        </div>

        <div class="mb-3">
          <label class="form-label"><?= h($T('Нікнейм','Никнейм','Username')) ?></label>
          <input class="form-control" name="username" value="<?= h($uname) ?>" maxlength="32" required>
          <div class="form-text"><?= h($T('3–32 символи: латиниця/цифри/_/-','3–32 символа: латиница/цифры/_/-','3–32 chars: latin/digits/_/-')) ?></div>
        </div>

        <div class="mb-3">
          <label class="form-label"><?= h($T("ПІБ","ФИО","Full name")) ?></label>
          <input class="form-control" name="full_name" value="<?= h($fullInput) ?>" maxlength="190" required>
        </div>

        <?php if ($hasGender): ?>
        <div class="mb-3">
          <label class="form-label"><?= h($T('Стать','Пол','Gender')) ?></label>
          <select class="form-select" name="gender" required>
            <option value=""><?= h($T('Оберіть','Выберите','Select')) ?></option>
            <option value="f" <?= $gender === 'f' ? 'selected' : '' ?>><?= h($T('Жіноча','Женский','Female')) ?></option>
            <option value="m" <?= $gender === 'm' ? 'selected' : '' ?>><?= h($T('Чоловіча','Мужской','Male')) ?></option>
          </select>
        </div>
        <?php endif; ?>

        <?php if ($birthCol !== ''): ?>
        <div class="mb-3">
          <label class="form-label"><?= h($T('Дата народження','Дата рождения','Birth date')) ?></label>
          <input class="form-control" type="date" name="birthdate" value="<?= h($birth) ?>">
        </div>
        <?php endif; ?>

        <?php if ($hasCountry): ?>
        <div class="mb-3">
          <label class="form-label"><?= h($T('Країна','Страна','Country')) ?></label>
          <input class="form-control" name="country" value="<?= h($country) ?>" maxlength="120">
        </div>
        <?php endif; ?>

        <div class="mb-3">
          <label class="form-label"><?= h($T('Місто','Город','City')) ?></label>
          <input class="form-control" name="city" value="<?= h($city) ?>" maxlength="120">
        </div>

        <?php if ($hasEducation): ?>
        <div class="mb-3">
          <label class="form-label"><?= h($T('Освіта','Образование','Education')) ?></label>
          <input class="form-control" name="education" value="<?= h($education) ?>" maxlength="255">
        </div>
        <?php endif; ?>

        <?php if ($workCol !== ''): ?>
        <div class="mb-3">
          <label class="form-label"><?= h($T('Місце роботи','Место работы','Workplace')) ?></label>
          <input class="form-control" name="workplace" value="<?= h($workplace) ?>" maxlength="255">
        </div>
        <?php endif; ?>

        <div class="mb-3">
          <label class="form-label"><?= h($T('Про себе','О себе','About')) ?></label>
          <textarea class="form-control" name="about" rows="5" style="resize:vertical;"><?= h($about) ?></textarea>
        </div>

        <hr class="my-3">

        <div class="fw-semibold mb-2"><?= h($T('Зміна паролю','Смена пароля','Change password')) ?></div>

        <?php if (!$hasPassCol): ?>
          <div class="text-muted small mb-2"><?= h($T('Поле паролю в БД не знайдено.','Поле пароля в БД не найдено.','Password column not found in DB.')) ?></div>
        <?php endif; ?>

        <div class="mb-3">
          <label class="form-label"><?= h($T('Поточний пароль','Текущий пароль','Current password')) ?></label>
          <input class="form-control" type="password" name="current_password" autocomplete="current-password" <?= $hasPassCol ? '' : 'disabled' ?>>
        </div>

        <div class="mb-3">
          <label class="form-label"><?= h($T('Новий пароль','Новый пароль','New password')) ?></label>
          <input class="form-control" type="password" name="new_password" autocomplete="new-password" <?= $hasPassCol ? '' : 'disabled' ?>>
        </div>

        <div class="mb-3">
          <label class="form-label"><?= h($T('Повторіть новий пароль','Повторите новый пароль','Repeat new password')) ?></label>
          <input class="form-control" type="password" name="new_password2" autocomplete="new-password" <?= $hasPassCol ? '' : 'disabled' ?>>
        </div>

        <div class="d-flex gap-2 flex-wrap">
          <button class="btn btn-primary" type="submit"><?= h($T('Зберегти','Сохранить','Save')) ?></button>
          <a class="btn btn-outline-primary" href="/profile/coins.php">VM Coins</a>
          <a class="btn btn-outline-secondary" href="<?= h($profileHref) ?>"><?= h($T('Скасувати','Отмена','Cancel')) ?></a>
        </div>
      </form>
    </div>

  </section>

  <aside>
    <div class="sidebar-sticky">
      <?php
        $rightBlock = __DIR__ . '/../blocks/groups.php';
        if (is_file($rightBlock)) {
          require $rightBlock;
        }

        $gamesBlock = __DIR__ . '/../blocks/games.php';
        if (is_file($gamesBlock)) {
          echo '<div class="mt-3">';
          require $gamesBlock;
          echo '</div>';
        }
      ?>
    </div>
  </aside>
</div>

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