<?php
declare(strict_types=1);

/**
 * /admin/attachments.php
 * Вкладення (реальний стан /upload):
 * - Загальний розмір /upload та кількість файлів (кеш 10 хв)
 * - Розбивка за типами: image / video / audio / other (кеш 10 хв)
 * - Найбільші файли (топ 15)
 * - Останні 5 файлів (по часу зміни/завантаження)
 * - (опційно) DB-вкладення постів/коментарів, якщо такі таблиці існують
 */

require_once __DIR__ . '/../../includes/start.php';
require_role(['admin']);

require_once __DIR__ . '/../_helpers.php';
require_once __DIR__ . '/../_sidebar.php';

$pdo = db();

$title = admin_tt('admin_attachments', 'Вкладення', 'Вложения', 'Attachments');

/* ===== SEO: адмінка НЕ індексується ===== */
$meta_robots = 'noindex, nofollow, noarchive, nosnippet';
$meta_desc   = '';
$canonical   = function_exists('abs_url') ? abs_url('/admin/attachments/') : '/admin/attachments/';
if (!headers_sent()) {
    header('X-Robots-Tag: noindex, nofollow, noarchive, nosnippet', true);
}

/* ===== fallback e() (якщо раптом десь старий _helpers) ===== */
if (!function_exists('e')) {
    function e($v): string {
        if ($v === null) return '';
        if (is_array($v)) {
            $v = json_encode($v, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } elseif (is_object($v)) {
            $v = method_exists($v, '__toString')
                ? (string)$v
                : json_encode($v, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            $v = (string)$v;
        }
        if ($v === false) $v = '';
        return htmlspecialchars((string)$v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }
}

/* ===== locate upload dir (upload або uploads) ===== */
$uploadPath = realpath(__DIR__ . '/../../upload');
$uploadWeb  = '/upload/';
if ($uploadPath === false) {
    $uploadPath = realpath(__DIR__ . '/../../uploads');
    $uploadWeb  = '/uploads/';
}
$uploadOk = ($uploadPath !== false && is_dir((string)$uploadPath));

/* ===== total folder size (cached) ===== */
$uploadSize = ['bytes' => 0, 'truncated' => false, 'files' => 0, 'cached' => true];
if ($uploadOk) {
    $uploadSize = admin_dir_size_cached((string)$uploadPath, 'upload_size', 600);
}

/* ===== scan breakdown + largest files + newest files (cached) ===== */
$scan = [
    'by_cat' => [
        'image' => ['files' => 0, 'bytes' => 0],
        'video' => ['files' => 0, 'bytes' => 0],
        'audio' => ['files' => 0, 'bytes' => 0],
        'other' => ['files' => 0, 'bytes' => 0],
    ],
    'largest' => [],
    'newest' => [],
    'files_scanned' => 0,
    'truncated' => false,
    'cached' => true,
];

$scanKey = 'upload_scan_breakdown_v3';
if ($uploadOk) {
    $cached = admin_cache_get($scanKey, 600);

    $hasCached =
        is_array($cached)
        && isset($cached['by_cat'], $cached['largest'], $cached['newest'], $cached['files_scanned'], $cached['truncated'])
        && is_array($cached['by_cat'])
        && is_array($cached['largest'])
        && is_array($cached['newest']);

    if ($hasCached) {
        // normalize keys in case of partial cache
        $by = (array)$cached['by_cat'];
        foreach (['image','video','audio','other'] as $k) {
            if (!isset($by[$k]) || !is_array($by[$k])) $by[$k] = ['files' => 0, 'bytes' => 0];
            $by[$k]['files'] = (int)($by[$k]['files'] ?? 0);
            $by[$k]['bytes'] = (int)($by[$k]['bytes'] ?? 0);
        }

        $scan = [
            'by_cat' => $by,
            'largest' => (array)$cached['largest'],
            'newest' => (array)$cached['newest'],
            'files_scanned' => (int)$cached['files_scanned'],
            'truncated' => (bool)$cached['truncated'],
            'cached' => true,
        ];
    } else {
        $maxFiles = 250000;
        $largestN = 15;
        $newestN  = 5;

        $byCat = [
            'image' => ['files' => 0, 'bytes' => 0],
            'video' => ['files' => 0, 'bytes' => 0],
            'audio' => ['files' => 0, 'bytes' => 0],
            'other' => ['files' => 0, 'bytes' => 0],
        ];
        $largest = [];
        $newest  = [];
        $filesScanned = 0;
        $truncated = false;

        $imgExt = ['jpg','jpeg','png','gif','webp','bmp','svg'];
        $vidExt = ['mp4','mkv','mov','webm','avi','m4v','3gp'];
        $audExt = ['mp3','wav','ogg','aac','flac','m4a','opus'];

        try {
            $it = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator((string)$uploadPath, FilesystemIterator::SKIP_DOTS)
            );

            foreach ($it as $f) {
                /** @var SplFileInfo $f */
                if (!$f->isFile()) continue;

                $filesScanned++;
                $size = (int)$f->getSize();
                $mtime = (int)$f->getMTime();

                $ext = strtolower((string)pathinfo($f->getFilename(), PATHINFO_EXTENSION));
                if ($ext !== '' && in_array($ext, $imgExt, true)) $cat = 'image';
                elseif ($ext !== '' && in_array($ext, $vidExt, true)) $cat = 'video';
                elseif ($ext !== '' && in_array($ext, $audExt, true)) $cat = 'audio';
                else $cat = 'other';

                $byCat[$cat]['files']++;
                $byCat[$cat]['bytes'] += $size;

                // rel path
                $full = (string)$f->getPathname();
                $rel = $full;
                $root = rtrim((string)$uploadPath, DIRECTORY_SEPARATOR);
                if ($root !== '' && str_starts_with($full, $root)) {
                    $rel = substr($full, strlen($root));
                    if ($rel === false) $rel = $full;
                }
                $rel = str_replace('\\', '/', $rel);
                if ($rel === '') $rel = '/';

                // keep top N largest
                $largest[] = ['path' => $rel, 'bytes' => $size, 'mtime' => $mtime];
                if (count($largest) > $largestN * 3) {
                    usort($largest, fn($a,$b) => ((int)$b['bytes'] <=> (int)$a['bytes']));
                    $largest = array_slice($largest, 0, $largestN);
                }

                // keep top N newest
                $newest[] = ['path' => $rel, 'bytes' => $size, 'mtime' => $mtime];
                if (count($newest) > $newestN * 5) {
                    usort($newest, fn($a,$b) => ((int)$b['mtime'] <=> (int)$a['mtime']));
                    $newest = array_slice($newest, 0, $newestN);
                }

                if ($filesScanned >= $maxFiles) {
                    $truncated = true;
                    break;
                }
            }
        } catch (Throwable $e) {
            // ignore scan errors
        }

        usort($largest, fn($a,$b) => ((int)$b['bytes'] <=> (int)$a['bytes']));
        $largest = array_slice($largest, 0, $largestN);

        usort($newest, fn($a,$b) => ((int)$b['mtime'] <=> (int)$a['mtime']));
        $newest = array_slice($newest, 0, $newestN);

        $scan = [
            'by_cat' => $byCat,
            'largest' => $largest,
            'newest' => $newest,
            'files_scanned' => $filesScanned,
            'truncated' => $truncated,
            'cached' => false,
        ];

        admin_cache_set($scanKey, [
            'by_cat' => $byCat,
            'largest' => $largest,
            'newest' => $newest,
            'files_scanned' => $filesScanned,
            'truncated' => $truncated,
        ]);
    }
}

/* ===== optional: DB attachments (posts/comments) ===== */
$hasPA = admin_table_exists($pdo, 'post_attachments');
$hasCA = admin_table_exists($pdo, 'comment_attachments');

$postFiles = $hasPA ? admin_safe_int($pdo, "SELECT COUNT(*) FROM post_attachments") : 0;
$commFiles = $hasCA ? admin_safe_int($pdo, "SELECT COUNT(*) FROM comment_attachments") : 0;

$postBytes = 0;
$commBytes = 0;

if ($hasPA && admin_column_exists($pdo, 'post_attachments', 'size_bytes')) {
    $postBytes = admin_safe_sum($pdo, "SELECT COALESCE(SUM(size_bytes),0) FROM post_attachments");
}
if ($hasCA && admin_column_exists($pdo, 'comment_attachments', 'size_bytes')) {
    $commBytes = admin_safe_sum($pdo, "SELECT COALESCE(SUM(size_bytes),0) FROM comment_attachments");
}

require __DIR__ . '/../../includes/header.php';
?>

<div class="row g-3">
  <div class="col-lg-9">

    <div class="d-flex align-items-center justify-content-between mb-2">
      <h1 class="h4 mb-0"><?= e(admin_tt('admin_attachments', 'Вкладення', 'Вложения', 'Attachments')) ?></h1>
      <a class="btn btn-sm btn-outline-secondary" href="/admin/"><?= e(admin_tt('admin_dashboard', 'Дашборд', 'Дашборд', 'Dashboard')) ?></a>
    </div>

    <div class="row g-3">
      <div class="col-md-4">
        <div class="card card-app p-3">
          <div class="text-muted small"><?= e(admin_tt('admin_upload_folder', 'Папка', 'Папка', 'Folder')) ?> <?= e($uploadWeb) ?></div>
          <div class="display-6 fw-bold">
            <?= $uploadOk ? e(admin_human_bytes((int)$uploadSize['bytes'])) : '—' ?>
          </div>
          <div class="text-muted small">
            <?php if ($uploadOk): ?>
              <?= e(admin_tt('admin_files', 'Файлів', 'Файлов', 'Files')) ?>: <?= (int)$uploadSize['files'] ?>
              <?php if (!empty($uploadSize['truncated'])): ?> · <?= e(admin_tt('admin_approx', 'приблизно', 'примерно', 'approx')) ?><?php endif; ?>
              <?php if (!empty($uploadSize['cached'])): ?> · <?= e(admin_tt('admin_cached', 'кеш', 'кеш', 'cached')) ?><?php endif; ?>
            <?php else: ?>
              <?= e(admin_tt('admin_upload_missing', 'Папка не знайдена', 'Папка не найдена', 'Folder not found')) ?>
            <?php endif; ?>
          </div>
        </div>
      </div>

      <div class="col-md-4">
        <div class="card card-app p-3">
          <div class="text-muted small"><?= e(admin_tt('admin_scan', 'Сканування', 'Сканирование', 'Scan')) ?></div>
          <div class="display-6 fw-bold"><?= (int)$scan['files_scanned'] ?></div>
          <div class="text-muted small">
            <?= e(admin_tt('admin_scanned_files', 'файлів проскановано', 'файлов просканировано', 'files scanned')) ?>
            <?php if (!empty($scan['truncated'])): ?> · <?= e(admin_tt('admin_truncated', 'обмежено', 'ограничено', 'limited')) ?><?php endif; ?>
            <?php if (!empty($scan['cached'])): ?> · <?= e(admin_tt('admin_cached', 'кеш', 'кеш', 'cached')) ?><?php endif; ?>
          </div>
        </div>
      </div>

      <div class="col-md-4">
        <div class="card card-app p-3">
          <div class="text-muted small"><?= e(admin_tt('admin_db_attachments', 'DB-вкладення (пости/коментарі)', 'DB-вложения (посты/комменты)', 'DB attachments (posts/comments)')) ?></div>
          <div class="display-6 fw-bold"><?= (int)($postFiles + $commFiles) ?></div>
          <div class="text-muted small">
            <?= e(admin_tt('posts', 'Пости', 'Посты', 'Posts')) ?>: <?= (int)$postFiles ?> · <?= e(admin_human_bytes((int)$postBytes)) ?>
            <br>
            <?= e(admin_tt('comments', 'Коментарі', 'Комментарии', 'Comments')) ?>: <?= (int)$commFiles ?> · <?= e(admin_human_bytes((int)$commBytes)) ?>
          </div>
        </div>
      </div>
    </div>

    <div class="card card-app p-3 mt-3">
      <div class="fw-bold mb-2"><?= e(admin_tt('admin_breakdown', 'Розбивка за типами (файлова система)', 'Разбивка по типам (файловая система)', 'Breakdown by type (filesystem)')) ?></div>

      <div class="table-responsive">
        <table class="table table-sm align-middle mb-0">
          <thead>
            <tr>
              <th><?= e(admin_tt('admin_type', 'Тип', 'Тип', 'Type')) ?></th>
              <th class="text-end"><?= e(admin_tt('admin_files', 'Файлів', 'Файлов', 'Files')) ?></th>
              <th class="text-end"><?= e(admin_tt('admin_size', 'Розмір', 'Размер', 'Size')) ?></th>
            </tr>
          </thead>
          <tbody>
            <?php
              $labels = [
                'image' => admin_tt('admin_type_image', 'Зображення', 'Изображения', 'Images'),
                'video' => admin_tt('admin_type_video', 'Відео', 'Видео', 'Video'),
                'audio' => admin_tt('admin_type_audio', 'Аудіо', 'Аудио', 'Audio'),
                'other' => admin_tt('admin_type_other', 'Інше', 'Другое', 'Other'),
              ];
            ?>
            <?php foreach (['image','video','audio','other'] as $k): ?>
              <tr>
                <td><?= e($labels[$k]) ?></td>
                <td class="text-end"><?= (int)($scan['by_cat'][$k]['files'] ?? 0) ?></td>
                <td class="text-end"><?= e(admin_human_bytes((int)($scan['by_cat'][$k]['bytes'] ?? 0))) ?></td>
              </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
      </div>

      <div class="text-muted small mt-2">
        <?= e(admin_tt(
          'admin_cache_note_breakdown',
          'Дані кешуються на 10 хв, щоб адмінка не гальмувала на великих папках.',
          'Данные кешируются на 10 мин, чтобы админка не тормозила на больших папках.',
          'Cached for 10 minutes to keep the admin fast on large folders.'
        )) ?>
      </div>
    </div>

    <div class="card card-app p-3 mt-3">
      <div class="fw-bold mb-2"><?= e(admin_tt('admin_last_files', 'Останні 5 файлів', 'Последние 5 файлов', 'Last 5 files')) ?></div>

      <div class="table-responsive">
        <table class="table table-sm align-middle mb-0">
          <thead>
            <tr>
              <th><?= e(admin_tt('admin_path', 'Шлях', 'Путь', 'Path')) ?></th>
              <th class="text-end"><?= e(admin_tt('admin_size', 'Розмір', 'Размер', 'Size')) ?></th>
              <th class="text-end"><?= e(admin_tt('admin_modified', 'Змінено', 'Изменено', 'Modified')) ?></th>
            </tr>
          </thead>
          <tbody>
            <?php if (!$uploadOk): ?>
              <tr><td colspan="3" class="text-muted small"><?= e(admin_tt('admin_upload_missing', 'Папка не знайдена', 'Папка не найдена', 'Folder not found')) ?></td></tr>
            <?php elseif (empty($scan['newest'])): ?>
              <tr><td colspan="3" class="text-muted small"><?= e(admin_tt('admin_no_data', 'Немає даних', 'Нет данных', 'No data')) ?></td></tr>
            <?php else: ?>
              <?php foreach ($scan['newest'] as $row): ?>
                <tr>
                  <td class="text-muted small"><?= e($uploadWeb . ltrim((string)($row['path'] ?? ''), '/')) ?></td>
                  <td class="text-end fw-bold"><?= e(admin_human_bytes((int)($row['bytes'] ?? 0))) ?></td>
                  <td class="text-end text-muted small"><?= e(date('Y-m-d H:i', (int)($row['mtime'] ?? 0))) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </div>

    <div class="card card-app p-3 mt-3">
      <div class="fw-bold mb-2"><?= e(admin_tt('admin_largest_files', 'Найбільші файли', 'Самые большие файлы', 'Largest files')) ?></div>

      <div class="table-responsive">
        <table class="table table-sm align-middle mb-0">
          <thead>
            <tr>
              <th><?= e(admin_tt('admin_path', 'Шлях', 'Путь', 'Path')) ?></th>
              <th class="text-end"><?= e(admin_tt('admin_size', 'Розмір', 'Размер', 'Size')) ?></th>
              <th class="text-end"><?= e(admin_tt('admin_modified', 'Змінено', 'Изменено', 'Modified')) ?></th>
            </tr>
          </thead>
          <tbody>
            <?php if (!$uploadOk): ?>
              <tr><td colspan="3" class="text-muted small"><?= e(admin_tt('admin_upload_missing', 'Папка не знайдена', 'Папка не найдена', 'Folder not found')) ?></td></tr>
            <?php elseif (empty($scan['largest'])): ?>
              <tr><td colspan="3" class="text-muted small"><?= e(admin_tt('admin_no_data', 'Немає даних', 'Нет данных', 'No data')) ?></td></tr>
            <?php else: ?>
              <?php foreach ($scan['largest'] as $row): ?>
                <tr>
                  <td class="text-muted small"><?= e($uploadWeb . ltrim((string)($row['path'] ?? ''), '/')) ?></td>
                  <td class="text-end fw-bold"><?= e(admin_human_bytes((int)($row['bytes'] ?? 0))) ?></td>
                  <td class="text-end text-muted small"><?= e(date('Y-m-d H:i', (int)($row['mtime'] ?? 0))) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>

      <div class="text-muted small mt-2">
        <?= e(admin_tt(
          'admin_cache_note',
          'Дані кешуються на 10 хв, щоб адмінка не гальмувала на великих папках.',
          'Данные кешируются на 10 мин, чтобы админка не тормозила на больших папках.',
          'Cached for 10 minutes to keep the admin fast on large folders.'
        )) ?>
      </div>
    </div>

  </div>

  <div class="col-lg-3">
    <?php admin_sidebar('attachments'); ?>
  </div>
</div>

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