<?php
declare(strict_types=1);

require_once __DIR__ . '/../helpers.php';
require_once __DIR__ . '/../auth/_auth.php';

// 未ログインならログインへ
auth_require_login();

// -------- 一覧の下準備（カテゴリ受取 → SQLite接続 → items取得） --------

// カテゴリ受け取り（英数/_/- のみ許可）
$categorySlug = isset($_GET['category']) ? (string)$_GET['category'] : '';
$categorySlug = preg_replace('~[^A-Za-z0-9_\-]+~', '', $categorySlug);

// SQLite 接続（db.php に統一）
require_once __DIR__ . '/../db.php';
$pdo = db();

// 現在の FEATURE_TOPIC（サイト設定）を取得
$featureTopic = '';
try {
    $stFt = $pdo->prepare('SELECT value FROM settings WHERE key = ? LIMIT 1');
    $stFt->execute(['FEATURE_TOPIC']);
    $featureTopic = (string)($stFt->fetchColumn() ?: '');
} catch (Throwable $e) {
    $featureTopic = '';
}

// テーブル（念のため作成）
$pdo->exec('CREATE TABLE IF NOT EXISTS items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    category   TEXT NOT NULL,
    title      TEXT NOT NULL DEFAULT "",
    body       TEXT NOT NULL DEFAULT "",
    asset_file TEXT NOT NULL DEFAULT "",
    active     INTEGER NOT NULL DEFAULT 1,
    created_at TEXT NOT NULL,
    updated_at TEXT NOT NULL
)');

// 既存DB互換：active列が無い環境向けに後付け（あれば例外→握りつぶし）
try { $pdo->exec('ALTER TABLE items ADD COLUMN active INTEGER NOT NULL DEFAULT 1'); } catch (Throwable $e) {}

// 互換のために定義だけ残す（以降のロジックが参照するため）
$pdoAdmin = null;
$attachedAdminDb = false;

// セッション＆CSRF（未発行なら作成）
if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
if (empty($_SESSION['_csrf'])) { $_SESSION['_csrf'] = bin2hex(random_bytes(32)); }

// ---------- 一括削除（選択行） ----------
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['bulk'] ?? '') === 'delete') {
    // CSRF
    $csrf = (string)($_POST['_csrf'] ?? '');
    if ($csrf === '' || !hash_equals($_SESSION['_csrf'] ?? '', $csrf)) {
        http_response_code(400);
        exit('Bad Request: invalid CSRF token');
    }

    // ID配列（整数化）
    $ids = array_filter(array_map('intval', (array)($_POST['ids'] ?? [])), fn($v) => $v > 0);
    if (!$ids) {
        header('Location: ./items.php?category=' . rawurlencode((string)($_POST['category'] ?? ''))
             . '&q='   . rawurlencode((string)($_POST['q'] ?? ''))
             . '&sort=' . rawurlencode((string)($_POST['sort'] ?? ''))
             . '&dir='  . rawurlencode((string)($_POST['dir'] ?? ''))
             . '&per='  . (int)($_POST['per'] ?? 20)
             . '&deleted=0');
        exit;
    }

    // 削除対象の rows 取得（id, category, asset_file）
    $ph = implode(',', array_fill(0, count($ids), '?'));
    $stmtPick = $pdo->prepare('SELECT id, category, asset_file FROM items WHERE id IN (' . $ph . ')');
    $stmtPick->execute($ids);
    $rowsPick = $stmtPick->fetchAll(PDO::FETCH_ASSOC) ?: [];

    // 物理削除対象ファイル名を収集（重複排除）
    $fileSet = []; // ['filename.ext' => true]
    $updir = realpath(__DIR__ . '/../uploads') ?: (__DIR__ . '/../uploads');

    // helpers
    $stCatId = $pdo->prepare('SELECT id FROM categories WHERE slug = ? LIMIT 1');
    $stKeysA = $pdo->prepare('SELECT "key" FROM fields WHERE category_id = ? AND type = "assets"');
    $stIvAll = $pdo->prepare('SELECT field_key, value FROM item_values WHERE item_id = ?');

    foreach ($rowsPick as $rp) {
        $iid  = (int)($rp['id'] ?? 0);
        $slug = (string)($rp['category'] ?? '');
        $afn  = (string)($rp['asset_file'] ?? '');
        if ($afn !== '') { $fileSet[$afn] = true; }

        if ($iid > 0 && $slug !== '') {
            // カテゴリ→assetsキー一覧
            $stCatId->execute([$slug]);
            $cid = (int)$stCatId->fetchColumn();
            if ($cid > 0) {
                $stKeysA->execute([$cid]);
                $keySet = [];
                foreach ($stKeysA->fetchAll(PDO::FETCH_COLUMN) ?: [] as $k) {
                    $k = (string)$k;
                    if ($k !== '') $keySet[$k] = true;
                }
                if (!empty($keySet)) {
                    // 対象アイテムの全値→assetsキーだけ拾う
                    $stIvAll->execute([$iid]);
                    foreach ($stIvAll->fetchAll(PDO::FETCH_ASSOC) ?: [] as $vrow) {
                        $fk = (string)($vrow['field_key'] ?? '');
                        $vv = (string)($vrow['value'] ?? '');
                        if ($vv !== '' && isset($keySet[$fk])) {
                            $fileSet[$vv] = true;
                        }
                    }
                }
            }
        }
    }

    // レコード削除（items / item_values）
    try {
        $stmtDel = $pdo->prepare('DELETE FROM items WHERE id IN (' . $ph . ')');
        $stmtDel->execute($ids);

        $stmtIv = $pdo->prepare('DELETE FROM item_values WHERE item_id IN (' . $ph . ')');
        $stmtIv->execute($ids);
    } catch (\Throwable $e) {
        http_response_code(500);
        exit('Internal Server Error: delete failed');
    }

    // 物理ファイル削除
    foreach (array_keys($fileSet) as $fn) {
        $fn = (string)$fn;
        if ($fn !== '') {
            $path = $updir . '/' . $fn;
            if (is_file($path)) { @unlink($path); }
        }
    }

    // 戻り（絞り込みやソートを保持）
    header('Location: ./items.php?category=' . rawurlencode((string)($_POST['category'] ?? ''))
         . '&q='   . rawurlencode((string)($_POST['q'] ?? ''))
         . '&sort=' . rawurlencode((string)($_POST['sort'] ?? ''))
         . '&dir='  . rawurlencode((string)($_POST['dir'] ?? ''))
         . '&per='  . (int)($_POST['per'] ?? 20)
         . '&deleted=' . count($ids));
    exit;
}

 // 新規作成フォームに前回入力（_flash_form）が残らないようクリア
 unset($_SESSION['_flash_form']);

// 特集トグル（POST）: item_values.PICKUP_TOPIC を FEATURE_TOPIC にセット/解除
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['_action'] ?? '') === 'feature_toggle') {
    // このアイテムのカテゴリにPICKUP_TOPICが無ければ無効化
    $stChk = $pdo->prepare(
        'SELECT 1
           FROM items i
           JOIN categories c ON c.slug = i.category
           JOIN fields f     ON f.category_id = c.id AND f."key" = "PICKUP_TOPIC"
          WHERE i.id = ?
          LIMIT 1'
    );
    $stChk->execute([ (int)($_POST['id'] ?? 0) ]);
    if (!$stChk->fetchColumn()) {
        header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&ok=1'); // 何もせず戻る
        exit;
    }
    if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
    $csrfPost = (string)($_POST['_csrf'] ?? '');
    if ($csrfPost === '' || !hash_equals((string)($_SESSION['_csrf'] ?? ''), $csrfPost)) {
        header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&err=' . rawurlencode('フォームの有効期限が切れました。もう一度お試しください。'));
        exit;
    }

    $idTgl = max(0, (int)($_POST['id'] ?? 0));
    $toOn  = (int)($_POST['to_on'] ?? 0) === 1;
    if ($idTgl > 0 && $featureTopic !== '') {
        try {
            if ($toOn) {
                // UPDATE → 0件なら INSERT
                $stU = $pdo->prepare('UPDATE item_values SET value = ? WHERE item_id = ? AND field_key = "PICKUP_TOPIC"');
                $stU->execute([$featureTopic, $idTgl]);
                if ($stU->rowCount() === 0) {
                    $stI = $pdo->prepare('INSERT INTO item_values(item_id, field_key, value) VALUES(?, "PICKUP_TOPIC", ?)');
                    $stI->execute([$idTgl, $featureTopic]);
                }
            } else {
                $stD = $pdo->prepare('DELETE FROM item_values WHERE item_id = ? AND field_key = "PICKUP_TOPIC"');
                $stD->execute([$idTgl]);
            }
        } catch (Throwable $e) {
            header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&err=' . rawurlencode('保存に失敗しました。'));
            exit;
        }
    }
    header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&ok=1');
    exit;
}

// 公開トグル（POST）
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['_action'] ?? '') === 'toggle') {
    if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
    $csrfPost = (string)($_POST['_csrf'] ?? '');
    if ($csrfPost === '' || !hash_equals((string)($_SESSION['_csrf'] ?? ''), $csrfPost)) {
        header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&err=' . rawurlencode('フォームの有効期限が切れました。もう一度お試しください。'));
        exit;
    }
    $idTgl = max(0, (int)($_POST['id'] ?? 0));
    $toActive = (int)($_POST['to_active'] ?? 0) === 1 ? 1 : 0;
    if ($idTgl > 0) {
        $stmt = $pdo->prepare('UPDATE items SET active=? WHERE id=?');
        $stmt->execute([$toActive, $idTgl]);
    }
    header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&ok=1');
    exit;
}

// 削除（POST）
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['_action'] ?? '') === 'delete') {
    $csrfPost = (string)($_POST['_csrf'] ?? '');
    if ($csrfPost === '' || !hash_equals((string)($_SESSION['_csrf'] ?? ''), $csrfPost)) {
        header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&err=' . rawurlencode('フォームの有効期限が切れました。もう一度お試しください。'));
        exit;
    }
    $idDel = max(0, (int)($_POST['id'] ?? 0));
    if ($idDel > 0) {
        // 削除対象の基本情報
        $stPick = $pdo->prepare('SELECT id, category, asset_file FROM items WHERE id = ?');
        $stPick->execute([$idDel]);
        if ($row = $stPick->fetch(PDO::FETCH_ASSOC)) {
            $slug = (string)($row['category'] ?? '');
            $afn  = (string)($row['asset_file'] ?? '');

            $fileSet = [];
            if ($afn !== '') $fileSet[$afn] = true;

            $updir = realpath(__DIR__ . '/../uploads') ?: (__DIR__ . '/../uploads');

            // カテゴリの assets キー → item_values のファイル名を収集
            if ($slug !== '') {
                $stCatId = $pdo->prepare('SELECT id FROM categories WHERE slug = ? LIMIT 1');
                $stCatId->execute([$slug]);
                $cid = (int)$stCatId->fetchColumn();

                if ($cid > 0) {
                    $stKeysA = $pdo->prepare('SELECT "key" FROM fields WHERE category_id = ? AND type = "assets"');
                    $stKeysA->execute([$cid]);
                    $keySet = [];
                    foreach ($stKeysA->fetchAll(PDO::FETCH_COLUMN) ?: [] as $k) {
                        $k = (string)$k;
                        if ($k !== '') $keySet[$k] = true;
                    }

                    if (!empty($keySet)) {
                        $stIvAll = $pdo->prepare('SELECT field_key, value FROM item_values WHERE item_id = ?');
                        $stIvAll->execute([$idDel]);
                        foreach ($stIvAll->fetchAll(PDO::FETCH_ASSOC) ?: [] as $vrow) {
                            $fk = (string)($vrow['field_key'] ?? '');
                            $vv = (string)($vrow['value'] ?? '');
                            if ($vv !== '' && isset($keySet[$fk])) {
                                $fileSet[$vv] = true;
                            }
                        }
                    }
                }
            }

            // レコード削除
            $pdo->prepare('DELETE FROM items WHERE id = ?')->execute([$idDel]);
            $pdo->prepare('DELETE FROM item_values WHERE item_id = ?')->execute([$idDel]);

            // 物理ファイル削除
            foreach (array_keys($fileSet) as $fn) {
                $fn = (string)$fn;
                if ($fn !== '') {
                    $path = $updir . '/' . $fn;
                    if (is_file($path)) { @unlink($path); }
                }
            }
        }
    }
    header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&ok=1');
    exit;
}

// 閲覧カウントのリセット（POST）
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['_action'] ?? '') === 'reset_views') {
    if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
    $csrfPost = (string)($_POST['_csrf'] ?? '');
    if ($csrfPost === '' || !hash_equals((string)($_SESSION['_csrf'] ?? ''), $csrfPost)) {
        header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&err=' . rawurlencode('フォームの有効期限が切れました。もう一度お試しください。'));
        exit;
    }

    // scope=item（従来の1件単位） / scope=category（カテゴリ全体）に対応
    $scope = (string)($_POST['scope'] ?? 'item');

    try {
        if ($scope === 'category') {
            // この画面で表示中のカテゴリに属するアイテムの閲覧数をまとめてリセット
            if ($categorySlug !== '') {
                $st = $pdo->prepare(
                    'DELETE FROM item_views_daily
                      WHERE item_id IN (
                        SELECT id FROM items WHERE category = ?
                      )'
                );
                $st->execute([$categorySlug]);
            }
        } else {
            // データ1件単位で閲覧数をリセット（既存動作）
            $idReset = max(0, (int)($_POST['id'] ?? 0));
            if ($idReset > 0) {
                $st = $pdo->prepare('DELETE FROM item_views_daily WHERE item_id = ?');
                $st->execute([$idReset]);
            }
        }
    } catch (Throwable $e) {
        header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&err=' . rawurlencode('閲覧数のリセットに失敗しました。'));
        exit;
    }

    header('Location: ./items.php?category=' . rawurlencode($categorySlug) . '&ok=1');
    exit;
}

// 一覧データ取得（並び替え・ページング対応）
$allowedSort = ['id', 'active', 'created_at', 'updated_at', 'views_total']; // 公開もソート対象に追加
$sortKey     = isset($_GET['sort']) ? (string)$_GET['sort'] : 'id';
if (!in_array($sortKey, $allowedSort, true)) {
    $sortKey = 'id';
}
$dirRaw = strtolower((string)($_GET['dir'] ?? 'desc'));
$dirSql = ($dirRaw === 'asc') ? 'ASC' : 'DESC';

$page = (int)($_GET['page'] ?? 1);
if ($page < 1) $page = 1;
$per  = (int)($_GET['per'] ?? 20);
if (!in_array($per, [20,50,100], true)) $per = 20;
$offset = ($page - 1) * $per;

// キーワード検索（タイトル部分一致）
$qRaw = (string)($_GET['q'] ?? '');
$q    = mb_substr(trim($qRaw), 0, 100, 'UTF-8'); // 安全のため100文字上限

$idRaw = (string)($_GET['id'] ?? '');
$idEq  = (ctype_digit($idRaw) ? (int)$idRaw : 0); // 数値IDのみ許可（0=無効）

// 共通 WHERE
$where  = '';
$params = [];
if ($categorySlug !== '') {
    $where = ' WHERE category = :category';
    $params[':category'] = $categorySlug;
}

if ($q !== '') {
    $where .= ($where === '' ? ' WHERE ' : ' AND ') . 'title LIKE :q';
    $params[':q'] = '%'.$q.'%';
}

if ($idEq > 0) {
    $where .= ($where === '' ? ' WHERE ' : ' AND ') . 'id = :id';
    $params[':id'] = $idEq;
}

// 件数
$sqlCount = 'SELECT COUNT(*) FROM items' . $where;
$stmtCount = $pdo->prepare($sqlCount);
foreach ($params as $k => $v) { $stmtCount->bindValue($k, $v, PDO::PARAM_STR); }
$stmtCount->execute();
$total = (int)$stmtCount->fetchColumn();
$totalPages = max(1, (int)ceil($total / $per));
if ($page > $totalPages) {
    $page   = $totalPages;
    $offset = ($page - 1) * $per;
}

// データ本体
$selectCols = 'items.id, items.category, items.title, items.asset_file, items.active, items.created_at, items.updated_at';

// 閲覧累計での並び替え指定かつ、ビュー表が存在する場合は JOIN して ORDER
$useViewsSort = ($sortKey === 'views_total');
$hasViewTblForOrder = false;
if ($useViewsSort) {
    try {
        $chk = $pdo->query("SELECT name FROM sqlite_master WHERE type='table' AND name='item_views_daily'");
        $hasViewTblForOrder = (bool)$chk->fetchColumn();
    } catch (Throwable $e) { $hasViewTblForOrder = false; }
}
if ($useViewsSort && !$hasViewTblForOrder) {
    $sortKey = 'id';          // ビュー表が無い環境では安全な既定に戻す
    $useViewsSort = false;    // 通常分岐へ
}

// JOIN版 WHERE（items. プレフィックスに合わせて再構築）
$sqlWhereItems = '';
$bind2 = $params; // 既存のバインド再利用
if ($categorySlug !== '') {
    $sqlWhereItems = ' WHERE items.category = :category';
}
if ($q !== '') {
    $sqlWhereItems .= ($sqlWhereItems==='' ? ' WHERE ' : ' AND ') . 'items.title LIKE :q';
}
if ($idEq > 0) {
    $sqlWhereItems .= ($sqlWhereItems==='' ? ' WHERE ' : ' AND ') . 'items.id = :id';
}

if ($useViewsSort && $hasViewTblForOrder) {
    // 閲覧累計で ORDER BY
    $sql =
        'SELECT ' . $selectCols . ', COALESCE(v.total,0) AS _v_total
           FROM items
      LEFT JOIN (
                SELECT item_id, SUM(count) AS total
                  FROM item_views_daily
              GROUP BY item_id
            ) v ON v.item_id = items.id'
        . $sqlWhereItems
        . ' ORDER BY _v_total ' . $dirSql . ', items.id DESC'
        . ' LIMIT ' . (int)$per . ' OFFSET ' . (int)$offset;

    $stmt = $pdo->prepare($sql);
    foreach ($bind2 as $k => $v) { $stmt->bindValue($k, $v, PDO::PARAM_STR); }

} else {
    // 従来通りの並び
    $sql = 'SELECT ' . $selectCols . ' FROM items' . $where
         . ' ORDER BY ' . $sortKey . ' ' . $dirSql . ', id DESC'
         . ' LIMIT ' . (int)$per . ' OFFSET ' . (int)$offset;

    $stmt = $pdo->prepare($sql);
    foreach ($params as $k => $v) { $stmt->bindValue($k, $v, PDO::PARAM_STR); }
}

$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];

/* ---- 閲覧数（累計のみ）をまとめて取得（テーブル未作成でも安全にスキップ） ---- */
$viewsMap = []; // [item_id => total]
if ($rows) {
    $ids = array_values(array_filter(array_map(fn($r)=> (int)($r['id'] ?? 0), $rows), fn($v)=> $v>0));
    if ($ids) {
        // テーブル存在チェック
        $hasViewTbl = false;
        try {
            $chk = $pdo->query("SELECT name FROM sqlite_master WHERE type='table' AND name='item_views_daily'");
            $hasViewTbl = (bool)$chk->fetchColumn();
        } catch (Throwable $e) { $hasViewTbl = false; }

        if ($hasViewTbl) {
            $ph = implode(',', array_fill(0, count($ids), '?'));
            $sqlV = 'SELECT item_id, SUM(count) AS total FROM item_views_daily WHERE item_id IN (' . $ph . ') GROUP BY item_id';
            $stV = $pdo->prepare($sqlV);
            try {
                $stV->execute($ids);
                foreach ($stV->fetchAll(PDO::FETCH_ASSOC) ?: [] as $v) {
                    $iid = (int)($v['item_id'] ?? 0);
                    if ($iid > 0) $viewsMap[$iid] = (int)($v['total'] ?? 0);
                }
            } catch (Throwable $e) {
                // 読み取りエラー時は静かに無視（0扱い）
            }
        }
    }
}

// 一覧表示に追加する「list_visible=1」の項目（最大3列）
$listFields = [];
$labelsMap  = []; // [key => [value => label]]
$ivMap      = []; // [item_id => [field_key => value]]

if ($categorySlug !== '') {
    // カテゴリID取得
    $stCid = $pdo->prepare('SELECT id FROM categories WHERE slug = ? LIMIT 1');
    $stCid->execute([$categorySlug]);
    $cid = (int)$stCid->fetchColumn();

    if ($cid > 0) {
        // 表示列（最大3）
        $stF = $pdo->prepare('SELECT "key", label, type, options FROM fields WHERE category_id = ? AND list_visible = 1 ORDER BY ord ASC, id ASC LIMIT 3');
        $stF->execute([$cid]);
        $listFields = $stF->fetchAll(PDO::FETCH_ASSOC) ?: [];

        // ラベル変換（select/radio/checkbox）
        foreach ($listFields as $lf) {
            $k = (string)($lf['key'] ?? '');
            $t = (string)($lf['type'] ?? '');
            $optJ = (string)($lf['options'] ?? '');
            if ($k === '' || $optJ === '') continue;
            if (in_array($t, ['select','radio','checkbox'], true)) {
                $arr = json_decode($optJ, true);
                if (is_array($arr)) {
                    $map = [];
                    foreach ($arr as $o) {
                        $v = isset($o['value']) ? (string)$o['value'] : '';
                        $l = isset($o['label']) ? (string)$o['label'] : $v;
                        if ($v !== '') $map[$v] = $l;
                    }
                    if ($map) $labelsMap[$k] = $map;
                }
            }
        }

        // このページで表示している item_id 群の値をまとめて取得
        if ($rows && $listFields) {
            $ids = array_values(array_filter(array_map(fn($r)=> (int)($r['id'] ?? 0), $rows), fn($v)=> $v>0));
            if ($ids) {
                $ph = implode(',', array_fill(0, count($ids), '?'));
                $stIv = $pdo->prepare('SELECT item_id, field_key, value FROM item_values WHERE item_id IN (' . $ph . ')');
                $stIv->execute($ids);
                foreach ($stIv->fetchAll(PDO::FETCH_ASSOC) ?: [] as $v) {
                    $iid = (int)($v['item_id'] ?? 0);
                    $fk  = (string)($v['field_key'] ?? '');
                    $val = (string)($v['value'] ?? '');
                    if ($iid > 0 && $fk !== '') {
                        if (!isset($ivMap[$iid])) $ivMap[$iid] = [];
                        $ivMap[$iid][$fk] = $val;
                    }
                }
            }
        }
    }
}

$hasPickupTopic = false;
if ($categorySlug !== '' && isset($cid) && (int)$cid > 0) {
    $stHas = $pdo->prepare('SELECT 1 FROM fields WHERE category_id = ? AND "key" = "PICKUP_TOPIC" LIMIT 1');
    $stHas->execute([(int)$cid]);
    $hasPickupTopic = (bool)$stHas->fetchColumn();
}

?><!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>データ一覧｜Template Party CMS</title>
  <link rel="stylesheet" href="<?= h(asset_url('/admin/assets/admin.css', true)) ?>">
</head>
<body class="admin items">
<?php include __DIR__ . '/_header.php'; ?>

<div id="container">
  <h1>データ一覧</h1>

  <?php if (isset($_GET['ok']) && (string)$_GET['ok'] === '1'): ?>
    <p class="ok">保存しました</p>
  <?php elseif (isset($_GET['err']) && (string)$_GET['err'] !== ''): ?>
    <p class="err"><?= htmlspecialchars((string)$_GET['err'], ENT_QUOTES, 'UTF-8') ?></p>
  <?php endif; ?>
  <?php if (isset($_GET['deleted'])): ?><p class="ok">削除しました（<?= (int)$_GET['deleted'] ?>件）</p><?php endif; ?>

  <p class="meta">
    カテゴリ: <span class="mono"><?= htmlspecialchars($categorySlug !== '' ? $categorySlug : '（全件）', ENT_QUOTES, 'UTF-8') ?></span>
    <?php if ($categorySlug !== ''): ?>
      <form method="post"
            action="./items.php?category=<?= rawurlencode($categorySlug) ?>"
            style="display:inline;margin-left:.5em;"
            onsubmit="return confirm('このカテゴリ内の全データの閲覧数をリセットします。よろしいですか？');">
        <input type="hidden" name="_csrf" value="<?= htmlspecialchars($_SESSION['_csrf'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
        <input type="hidden" name="_action" value="reset_views">
        <input type="hidden" name="scope" value="category">
        <button type="submit">
          このカテゴリの閲覧数をリセット
        </button>
      </form>
    <?php endif; ?>
  </p>

  <?php if ($categorySlug !== ''): ?>
  <div class="mb1rem">
    <a class="btn1" href="./regist.php?category=<?= rawurlencode($categorySlug) ?>&id=new">新規作成</a>
  </div>
  <?php endif; ?>

  <form method="get" action="./items.php" class="mb1rem">
    <input type="hidden" name="category" value="<?= htmlspecialchars($categorySlug, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="sort"     value="<?= htmlspecialchars($sortKey, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="dir"      value="<?= htmlspecialchars($dirRaw, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="per"      value="<?= (int)$per ?>">

    <label for="js-q">キーワード：</label>
    <input id="js-q" class="input-default" type="search" name="q"
           value="<?= htmlspecialchars($q, ENT_QUOTES, 'UTF-8') ?>"
           placeholder="タイトルを検索">

    <label for="js-id" style="margin-left:.6rem;">ID：</label>
    <input id="js-id" class="input-default" type="number" name="id" min="1" step="1"
               value="<?= ($idEq > 0 ? (string)$idEq : '') ?>">

    <button type="submit">検索</button>
    <?php if ($q !== '' || ($idEq ?? 0) > 0): ?>
      <a href="./items.php?category=<?= rawurlencode($categorySlug) ?>">クリア</a>
    <?php endif; ?>
  </form>

  <form method="get" action="./items.php" class="mb1rem">
    <input type="hidden" name="category" value="<?= htmlspecialchars($categorySlug, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="sort"     value="<?= htmlspecialchars($sortKey, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="dir"      value="<?= htmlspecialchars($dirRaw, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="q"        value="<?= htmlspecialchars($q, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="page"     value="1">
    <label for="js-per">表示件数：</label>
    <select id="js-per" class="input" name="per" onchange="this.form.submit()">
      <option value="20"  <?= ($per===20  ? 'selected' : '') ?>>20件</option>
      <option value="50"  <?= ($per===50  ? 'selected' : '') ?>>50件</option>
      <option value="100" <?= ($per===100 ? 'selected' : '') ?>>100件</option>
    </select>
    <noscript><button type="submit" class="btn1 ml05rem">変更</button></noscript>
  </form>

  <?php if (!$rows): ?>
    <p>データがありません。</p>
  <?php endif; ?>

  <div class="table-wrap">
  
  <!-- 一括削除フォームは分離（ネスト回避） -->
  <form id="bulk-form" method="post" action="./items.php">
    <input type="hidden" name="_csrf"    value="<?= htmlspecialchars($_SESSION['_csrf'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="bulk"     value="delete">
    <input type="hidden" name="category" value="<?= htmlspecialchars($categorySlug, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="q"        value="<?= htmlspecialchars($q, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="sort"     value="<?= htmlspecialchars($sortKey, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="dir"      value="<?= htmlspecialchars($dirRaw, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="per"      value="<?= (int)$per ?>">
    <input type="hidden" name="id"       value="<?= ($idEq > 0 ? (string)$idEq : '') ?>">
  </form>

    <table class="ta1">
      <thead>
        <tr>
          <th class="checkbox">
            <input type="checkbox" id="js-check-all" onclick="document.querySelectorAll('.js-check').forEach(cb=>cb.checked=this.checked)">
          </th>
          <th class="id">
            <a href="./items.php?category=<?= rawurlencode($categorySlug) ?>&sort=id&dir=<?= ($sortKey==='id' && $dirRaw==='asc') ? 'desc' : 'asc' ?>&q=<?= rawurlencode($q) ?>&id=<?= (int)($idEq ?? 0) ?>&per=<?= (int)$per ?>">
              ID<?= ($sortKey==='id' ? ($dirRaw==='asc' ? '▲' : '▼') : '') ?>
            </a>
          </th>
          <?php if ($categorySlug === ''): ?><th class="category">カテゴリ</th><?php endif; ?>
          <th class="title">タイトル</th>
          <?php if (!empty($listFields)): foreach ($listFields as $lf): ?>
            <th class="slug"><?= h((string)($lf['label'] ?? (string)($lf['key'] ?? ''))) ?></th>
          <?php endforeach; endif; ?>
          <?php if ($hasPickupTopic && $featureTopic !== '' && $categorySlug !== ''): ?>
            <th class="feature">特集</th>
          <?php endif; ?>
          <th class="date">
            <a href="./items.php?category=<?= rawurlencode($categorySlug) ?>&sort=views_total&dir=<?= ($sortKey==='views_total' && $dirRaw==='asc') ? 'desc' : 'asc' ?>&q=<?= rawurlencode($q) ?>&id=<?= (int)($idEq ?? 0) ?>&per=<?= (int)$per ?>">
              閲覧<?= ($sortKey==='views_total' ? ($dirRaw==='asc' ? '▲' : '▼') : '') ?>
            </a>
          </th>
          <th class="date">
            <a href="./items.php?category=<?= rawurlencode($categorySlug) ?>&sort=created_at&dir=<?= ($sortKey==='created_at' && $dirRaw==='asc') ? 'desc' : 'asc' ?>&q=<?= rawurlencode($q) ?>&id=<?= (int)($idEq ?? 0) ?>&per=<?= (int)$per ?>">
              登録日<?= ($sortKey==='created_at' ? ($dirRaw==='asc' ? '▲' : '▼') : '') ?>
            </a>
          </th>
          <th class="date">
            <a href="./items.php?category=<?= rawurlencode($categorySlug) ?>&sort=updated_at&dir=<?= ($sortKey==='updated_at' && $dirRaw==='asc') ? 'desc' : 'asc' ?>&q=<?= rawurlencode($q) ?>&id=<?= (int)($idEq ?? 0) ?>&per=<?= (int)$per ?>">
              更新日<?= ($sortKey==='updated_at' ? ($dirRaw==='asc' ? '▲' : '▼') : '') ?>
            </a>
          </th>
          <th class="btn-table">操作</th>
        </tr>
      </thead>
      <tbody>
        <?php if ($rows): ?>
          <?php foreach ($rows as $r): ?>
            <?php
              $catForLink = ($categorySlug !== '') ? $categorySlug : (string)($r['category'] ?? '');
              $idForLink  = (int)$r['id'];
              $titleDisp  = htmlspecialchars((string)$r['title'], ENT_QUOTES, 'UTF-8');
              $dateDisp   = htmlspecialchars(substr((string)$r['created_at'], 0, 10), ENT_QUOTES, 'UTF-8');
              $updatedDisp = htmlspecialchars(substr((string)$r['updated_at'], 0, 10), ENT_QUOTES, 'UTF-8');
            ?>
            <tr>
              <td class="checkbox"><input type="checkbox" class="js-check" name="ids[]" value="<?= (int)$r['id'] ?>" form="bulk-form"></td>
              <td class="id"><?= $idForLink ?></td>
              <?php if ($categorySlug === ''): ?>
                <td class="category"><?= htmlspecialchars((string)($r['category'] ?? ''), ENT_QUOTES, 'UTF-8') ?></td>
              <?php endif; ?>
              <td class="title">
                <span class="cell-title">
                  <a href="./regist.php?category=<?= rawurlencode($catForLink) ?>&id=<?= $idForLink ?>"><?= $titleDisp ?></a>
                </span>
              </td>
              <?php if (!empty($listFields)): ?>
                <?php foreach ($listFields as $lf): ?>
                  <?php
                    $k = (string)($lf['key'] ?? '');
                    $t = (string)($lf['type'] ?? '');
                    $raw = (string)($ivMap[$idForLink][$k] ?? '');
                    $disp = '—';
                    if ($raw !== '') {
                        if ($t === 'assets') {
                            $disp = '有';
                        } elseif ($t === 'checkbox') {
                            $parts = array_values(array_filter(array_map('trim', explode(',', $raw)), 'strlen'));
                            if ($parts) {
                                $labels = array_map(function($v) use ($k, $labelsMap){ return (string)($labelsMap[$k][$v] ?? $v); }, $parts);
                                $disp = implode('、', $labels);
                            }
                        } elseif (in_array($t, ['select','radio'], true)) {
                            $disp = (string)($labelsMap[$k][$raw] ?? $raw);
                        } else {
                            $disp = $raw;
                            if (function_exists('mb_substr')) { $disp = mb_substr($disp, 0, 40, 'UTF-8'); }
                            else { if (strlen($disp) > 40) $disp = substr($disp, 0, 40); }
                        }
                    }
                  ?>
                  <td class="slug"><?= h($disp) ?></td>
                <?php endforeach; ?>
              <?php endif; ?>
              <?php
                // この行の特集状態（PICKUP_TOPIC）が現在の FEATURE_TOPIC と一致しているか
                $pickRaw = (string)($ivMap[$idForLink]['PICKUP_TOPIC'] ?? '');
                $isPicked = ($featureTopic !== '' && $pickRaw === $featureTopic);
              ?>
              <?php if ($hasPickupTopic && $featureTopic !== '' && $categorySlug !== ''): ?>
              <td class="feature">
                <?php
                  // この行の特集状態（PICKUP_TOPIC）が現在の FEATURE_TOPIC と一致しているか
                  $pickRaw  = (string)($ivMap[$idForLink]['PICKUP_TOPIC'] ?? '');
                  $isPicked = ($featureTopic !== '' && $pickRaw === $featureTopic);
                ?>
                <?php if ($featureTopic === ''): ?>
                  —
                <?php else: ?>
                  <div class="btns">
                    <form method="post" action="./items.php?category=<?= rawurlencode($catForLink) ?>">
                      <input type="hidden" name="_csrf" value="<?= htmlspecialchars($_SESSION['_csrf'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
                      <input type="hidden" name="_action" value="feature_toggle">
                      <input type="hidden" name="id" value="<?= $idForLink ?>">
                      <input type="hidden" name="to_on" value="<?= $isPicked ? 0 : 1 ?>">
                      <button type="submit" class="btn">
                        <?php if ($isPicked): ?>
                          <img src="assets/star-solid-active.svg" alt="特集ON" title="特集ON">
                        <?php else: ?>
                          <img src="assets/star-solid.svg" alt="特集OFF" title="特集OFF">
                        <?php endif; ?>
                      </button>
                    </form>
                  </div>
                <?php endif; ?>
              </td>
              <?php endif; ?>
              <?php $vt = (int)($viewsMap[$idForLink] ?? 0); ?>
              <td class="views"><?= $vt ?></td>
              <td class="active"><?= ((int)($r['active'] ?? 1) === 1) ? '公開' : '非公開' ?></td>
              <td class="date"><?= $dateDisp ?></td>
              <td class="date"><?= $updatedDisp ?></td>
              <td class="btn-table">
                <div class="btns">
                  <form method="post" action="./items.php?category=<?= rawurlencode($catForLink) ?>">
                    <input type="hidden" name="_csrf" value="<?= htmlspecialchars($_SESSION['_csrf'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
                    <input type="hidden" name="_action" value="toggle">
                    <input type="hidden" name="id" value="<?= $idForLink ?>">
                    <?php $isActive = (int)($r['active'] ?? 1) === 1; ?>
                    <?php if ($isActive): ?>
                      <input type="hidden" name="to_active" value="0">
                      <button type="submit" class="btn" title="公開">
                        <img src="assets/lock-open-solid.svg" alt="公開" title="公開">
                      </button>
                    <?php else: ?>
                      <input type="hidden" name="to_active" value="1">
                      <button type="submit" class="btn" title="非公開">
                        <img src="assets/lock-solid.svg" alt="非公開" title="非公開">
                      </button>
                    <?php endif; ?>
                  </form>
                  <a class="btn" href="./regist.php?category=<?= rawurlencode($catForLink) ?>&id=<?= $idForLink ?>&mode=copy">
                    <img src="assets/copy-solid.svg" alt="複製" title="複製">
                  </a>
                  <form method="post" action="./items.php?category=<?= rawurlencode($catForLink) ?>" onsubmit="return confirm('このデータを削除します。よろしいですか？');">
                    <input type="hidden" name="_csrf" value="<?= htmlspecialchars($_SESSION['_csrf'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
                    <input type="hidden" name="_action" value="delete">
                    <input type="hidden" name="id" value="<?= $idForLink ?>">
                    <button type="submit" class="btn danger"><img src="assets/trash-can-solid.svg" alt="削除" title="削除"></button>
                  </form>
                </div>
              </td>
            </tr>
          <?php endforeach; ?>
        <?php endif; ?>
      </tbody>
      
      <?php
      // 新規作成フォームに一覧用ループ変数 $r が流入しないようクリア
      unset($r);
      ?>

    </table>
      <button type="submit" class="mb1rem" form="bulk-form" onclick="return confirm('選択したデータを削除します。よろしいですか？')">選択を削除</button>

  </div>

  <?php
    // ページャ（番号リンク式）
    $qsBase = './items.php?category=' . rawurlencode($categorySlug)
            . '&sort=' . rawurlencode($sortKey)
            . '&dir='  . rawurlencode($dirRaw)
            . '&per='  . $per
            . '&q='    . rawurlencode($q)
            . '&id='   . (($idEq > 0) ? (string)$idEq : '');

    if ($totalPages > 1) {
        $window = 5; // 何ページ分表示するか（例：5）
        $half   = intdiv($window - 1, 2);

        $start = max(1, $page - $half);
        $end   = min($totalPages, $start + $window - 1);
        // 末尾寄りで不足が出た場合の補正
        $start = max(1, $end - $window + 1);
  ?>
  <div class="pager">
    <?php if ($page > 1): ?>
      <a href="<?= $qsBase . '&page=' . ($page - 1) ?>">&laquo; 前へ</a>
    <?php else: ?>
      <span>&laquo; 前へ</span>
    <?php endif; ?>

    <?php for ($i = $start; $i <= $end; $i++): ?>
      <?php if ($i === $page): ?>
        <span><?= (int)$i ?></span>
      <?php else: ?>
        <a href="<?= $qsBase . '&page=' . $i ?>"><?= (int)$i ?></a>
      <?php endif; ?>
    <?php endfor; ?>

    <?php if ($page < $totalPages): ?>
      <a href="<?= $qsBase . '&page=' . ($page + 1) ?>">次へ &raquo;</a>
    <?php else: ?>
      <span>次へ &raquo;</span>
    <?php endif; ?>
  </div>
  <?php } ?>

  <?php if ($categorySlug !== ''): ?>
  <div class="mb1rem">
    <a class="btn1" href="./regist.php?category=<?= rawurlencode($categorySlug) ?>&id=new">新規作成</a>
  </div>
  <?php endif; ?>

<script src="<?= h(asset_url('/admin/assets/admin.js', true)) ?>"></script>
</body>
</html>
