<?php
declare(strict_types=1);

require_once __DIR__ . '/../auth/_auth.php';
require_once __DIR__ . '/../security/_csrf.php';

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

require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../app/fields.php'; // ★ 初回アクセス時に fields テーブルを保証

// h() ヘルパ（既存に tpcms_h がある場合はそちら優先）
if (!function_exists('tpcms_h')) {
    function tpcms_h(string $s): string {
        return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }
}

// DB
$pdo = db();
/* ---- delete ---- */
// カテゴリ一覧
$catsStmt = $pdo->query('SELECT id, name, slug FROM categories ORDER BY id ASC');
$categories = $catsStmt ? $catsStmt->fetchAll(PDO::FETCH_ASSOC) : [];

 // 選択中カテゴリ（cat / category_id / id のいずれかで受け取る）
 $selectedCatId = null;
 foreach (['cat','category_id','id'] as $k) {
     if (isset($_GET[$k])) {
         $raw = is_array($_GET[$k]) ? reset($_GET[$k]) : $_GET[$k];
         $val = (string)$raw;
         if (preg_match('/^\d+$/', $val)) { $selectedCatId = (int)$val; break; }
     }
 }
 if ($selectedCatId === null && !empty($categories)) {
     $selectedCatId = (int)$categories[0]['id'];
 }

/* ---------- LD-03: create/delete field (POST) ---------- */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    csrf_check_or_die();
    $act = $_POST['_action'] ?? '';

    /* ---- create ---- */
    if ($act === 'create' && $selectedCatId !== null) {
        $label   = trim((string)($_POST['label'] ?? ''));
        $key     = trim((string)($_POST['key'] ?? ''));
        $type    = trim((string)($_POST['type'] ?? ''));
        $unit    = trim((string)($_POST['unit'] ?? ''));
        $options = (string)($_POST['options'] ?? '');

        // flags
        $required   = !empty($_POST['required'])     ? 1 : 0;
        $searchable = !empty($_POST['searchable'])   ? 1 : 0;
        $listVis    = !empty($_POST['list_visible']) ? 1 : 0;
        $sortable   = !empty($_POST['sortable'])     ? 1 : 0;
        $listSite   = !empty($_POST['list_site'])    ? 1 : 0;
        $detailSite = !empty($_POST['detail_site'])  ? 1 : 0;

        if (!in_array($type, ['number','currency','date'], true)) { $sortable = 0; }

        // basic validation
        $okTypes = ['text','textarea','select','radio','checkbox','number','currency','date','assets','map_iframe'];
        if ($label === '' || $key === '' || !preg_match('/^[A-Za-z0-9_-]+$/', $key) || !in_array($type, $okTypes, true)) {
            header('Location: ./fields.php?cat='.(string)$selectedCatId.'&err=invalid');
            exit;
        }

        // unique (category_id, "key")
        $st = $pdo->prepare('SELECT 1 FROM fields WHERE category_id = ? AND "key" = ? LIMIT 1');
        $st->execute([$selectedCatId, $key]);
        if ($st->fetchColumn()) {
            header('Location: ./fields.php?cat='.(string)$selectedCatId.'&err=dupkey');
            exit;
        }

         // 先頭に差し込む：既存を+1してスペースを作る → 新規は ord=1
         $pdo->prepare('UPDATE fields SET ord = ord + 1 WHERE category_id = ?')->execute([$selectedCatId]);
         $ord = 1;

        // insert
        $ins = $pdo->prepare('INSERT INTO fields
            (category_id, label, "key", type, required, searchable, list_visible, list_site, detail_site, sortable, unit, options, ord)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
        $ins->execute([
            $selectedCatId, $label, $key, $type,
            $required, $searchable, $listVis, $listSite, $detailSite, $sortable,
            ($unit !== '' ? $unit : null),
            fields_normalize_options($type, $options),
            $ord
        ]);

        header('Location: ./fields.php?cat='.(string)$selectedCatId.'&ok=1');
        exit;
    }

    /* ---- move (swap ord) ---- */
    if ($act === 'move') {
        $id  = (int)($_POST['id']  ?? 0);
        $dir = (string)($_POST['dir'] ?? '');

        if ($id > 0 && ($dir === 'up' || $dir === 'down')) {
            $st = $pdo->prepare('SELECT id, category_id, ord FROM fields WHERE id = ?');
            $st->execute([$id]);
            if ($cur = $st->fetch(PDO::FETCH_ASSOC)) {
                $catId = (int)$cur['category_id'];
                $ord   = (int)$cur['ord'];

                if ($dir === 'up') {
                    $nb = $pdo->prepare('SELECT id, ord FROM fields WHERE category_id = ? AND ord < ? ORDER BY ord DESC, id DESC LIMIT 1');
                    $nb->execute([$catId, $ord]);
                } else { // down
                    $nb = $pdo->prepare('SELECT id, ord FROM fields WHERE category_id = ? AND ord > ? ORDER BY ord ASC, id ASC LIMIT 1');
                    $nb->execute([$catId, $ord]);
                }

                if ($n = $nb->fetch(PDO::FETCH_ASSOC)) {
                    $nid  = (int)$n['id'];
                    $nord = (int)$n['ord'];

                    $pdo->beginTransaction();
                    $u1 = $pdo->prepare('UPDATE fields SET ord = ? WHERE id = ?');
                    $u2 = $pdo->prepare('UPDATE fields SET ord = ? WHERE id = ?');
                    $u1->execute([$nord, $id]);
                    $u2->execute([$ord,  $nid]);
                    $pdo->commit();
                }

                header('Location: ./fields.php?cat='.(string)$catId);
                exit;
            }
        }
        // 不正時はそのまま一覧へ
        $redirCat = $selectedCatId !== null ? (int)$selectedCatId : 0;
        $qs = $redirCat > 0 ? ('?cat='.(string)$redirCat) : '';
        header('Location: ./fields.php'.$qs);
        exit;
    }

    /* ---- sort (reorder by ids[]) ---- */
    if ($act === 'sort') {
        $ids = $_POST['ids'] ?? [];
        if (is_array($ids) && !empty($ids)) {
            // すべて整数に
            $ids = array_values(array_filter(array_map(function ($v) {
                $s = is_array($v) ? reset($v) : $v;
                return preg_match('/^\d+$/', (string)$s) ? (int)$s : null;
            }, $ids), fn($v) => $v !== null));

            if (!empty($ids)) {
                // 先頭IDからカテゴリを確認
                $st = $pdo->prepare('SELECT category_id FROM fields WHERE id = ?');
                $st->execute([$ids[0]]);
                $catId = (int)($st->fetchColumn() ?: 0);

                if ($catId > 0) {
                    // そのカテゴリのids[]のみを対象に1,2,3…で再採番
                    $pdo->beginTransaction();
                    $ord = 1;
                    $up  = $pdo->prepare('UPDATE fields SET ord = ? WHERE id = ? AND category_id = ?');
                    foreach ($ids as $fid) {
                        $up->execute([$ord++, (int)$fid, $catId]);
                    }
                    $pdo->commit();
                }
            }
        }
        // fetch からの呼び出しを想定。JS側でリロードするので即終了
        header('Content-Type: application/json; charset=UTF-8');
        echo '{"ok":true}';
        exit;
    }

    /* ---- delete ---- */
    if ($act === 'delete') {
        $id = (int)($_POST['id'] ?? 0);
        if ($id > 0) {
            // 対象のカテゴリIDを取得（リダイレクト先を決めるため）
            $st = $pdo->prepare('SELECT category_id FROM fields WHERE id = ?');
            $st->execute([$id]);
            $catId = (int)($st->fetchColumn() ?: 0);

            if ($catId > 0) {
                $del = $pdo->prepare('DELETE FROM fields WHERE id = ?');
                $del->execute([$id]);

                $redirCat = $selectedCatId !== null ? (int)$selectedCatId : $catId;
                header('Location: ./fields.php?cat='.(string)$redirCat.'&deleted=1');
                exit;
            }
        }
        // 不正時はそのまま一覧へ
        $redirCat = $selectedCatId !== null ? (int)$selectedCatId : 0;
        $qs = $redirCat > 0 ? ('?cat='.(string)$redirCat) : '';
        header('Location: ./fields.php'.$qs);
        exit;
    }
}

// フィールド一覧（選択カテゴリがある場合のみ）
$fields = [];
if ($selectedCatId !== null) {
    $stmt = $pdo->prepare('SELECT id, label, "key", type, searchable, list_visible, list_site, detail_site, sortable, ord
                           FROM fields
                           WHERE category_id = ?
                           ORDER BY ord ASC, id ASC');
    $stmt->execute([$selectedCatId]);
    $fields = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
}

$__err = isset($_GET['err']) ? (string)$_GET['err'] : '';
$__errMsg = ($__err === 'invalid') ? '入力内容に不備があります（ラベル/キー/型を確認）'
          : (($__err === 'dupkey') ? 'このカテゴリ内で同じキーが既に使われています' : '');
$__ok = isset($_GET['ok']) ? (string)$_GET['ok'] : '';
$__okMsg = ($__ok === '1') ? '保存しました' : '';
$__deleted = isset($_GET['deleted']) ? (string)$_GET['deleted'] : '';
$__deletedMsg = ($__deleted !== '') ? '削除しました' : '';

$__catName = '';
$__catSlug = '';
foreach ($categories as $c) { if ((int)$c['id'] === (int)$selectedCatId) { $__catName = (string)$c['name']; $__catSlug = (string)$c['slug']; break; } }

?><!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="./assets/admin.css">
</head>
<body class="admin fields">

<header>
  <div>
    <a href="./">ダッシュボード</a>
    <a href="../" target="_blank" rel="noopener">公開側トップ</a>
  </div>
  <div>
    <a href="./logout.php">ログアウト</a>
  </div>
</header>

<div id="container">

  <h1>項目設計</h1>
  
  <?php if ($__errMsg !== ''): ?>
  <p class="err"><?= tpcms_h($__errMsg) ?></p>
  <?php endif; ?>
  
  <?php if ($__okMsg !== ''): ?>
  <p class="ok"><?= tpcms_h($__okMsg) ?></p>
  <?php endif; ?>

  <?php if ($__deletedMsg !== ''): ?>
    <p class="ok"><?= tpcms_h($__deletedMsg) ?></p>
  <?php endif; ?>

  <?php if (empty($categories)): ?>
    <div class="mb1rem">先に<a href="./categories.php">カテゴリ</a>を作成してください。</div>
  <?php else: ?>
    <div class="row">
      <span class="label">カテゴリ</span>
      <div><?= tpcms_h($__catName) ?> (<?= tpcms_h($__catSlug) ?>)</div>
    </div>

    <div class="mb1rem">

      <form method="post" action="./fields.php?cat=<?= tpcms_h((string)$selectedCatId) ?>">
      <?= csrf_input_tag() ?>
        <input type="hidden" name="_action" value="create">

        <div class="row">
          <label class="label" for="f_label">ラベル</label>
          <input class="input" type="text" id="f_label" name="label" placeholder="例）家賃" required>
        </div>

        <div class="row">
          <label class="label" for="f_key">キー</label>
          <input class="input" type="text" id="f_key" name="key" placeholder="例）RENT（英数/_/-）" pattern="[A-Za-z0-9_-]+" required>
        </div>

        <div class="row">
          <label class="label" for="f_type">型</label>
          <select class="input" id="f_type" name="type" required>
            <option value="text">１行テキスト入力（text）</option>
            <option value="textarea">複数行テキスト入力（textarea）</option>
            <option value="select">プルダウン（select）</option>
            <option value="radio">ラジオボタン（radio）</option>
            <option value="checkbox">チェックボックス（checkbox）</option>
            <option value="number">数値（number）</option>
            <option value="currency">金額（currency）</option>
            <option value="date">日付（date）</option>
            <option value="assets">画像・動画（assets）</option>
            <option value="map_iframe">Google Map のiframe地図埋め込み（map_iframe）</option>
          </select>
        </div>

        <div class="row block">
          <label class="label">フラグ</label>
          <label><input type="checkbox" name="searchable" value="1"> 検索：サイト側のキーワード／絞り込みの対象にする</label>
          <label><input type="checkbox" name="list_visible" value="1"> 一覧（管理）：管理ページのデータ一覧の表に列を追加（最大3列）</label>
          <label><input type="checkbox" name="list_site" value="1"> 一覧（サイト）：一覧ページに出力させる</label>
          <label><input type="checkbox" name="detail_site" value="1"> 詳細（サイト）：詳細ページに出力させる</label>
        </div>

        <div class="row">
          <label class="label" for="f_unit">単位</label>
          <input class="input" type="text" id="f_unit" name="unit" placeholder="例）万円・m² など">
        </div>

        <div class="row">
          <label class="label" for="f_options">options（選択肢や制約）</label>
          <textarea class="input" id="f_options" name="options" placeholder="例）select/radio/checkbox は 1行1項目（value|label）&#10;number は {&quot;min&quot;:0,&quot;max&quot;:999,&quot;step&quot;:1} など"></textarea>
        </div>

        <div><button class="btn1 mb1rem" type="submit">保存する</button></div>
      </form>
    </div>

    <input type="hidden" id="csrf_token" value="<?= tpcms_h(csrf_get_token()) ?>">
    <div class="table-wrap">
      <table class="ta1">
        <thead>
          <tr>
            <th class="handle" aria-label="ドラッグで並び替え">☰</th>
            <th class="title">ラベル</th>
            <th class="slug">キー</th>
            <th class="slug">入力タイプ</th>
            <th class="active">検索</th>
            <th class="active">一覧<span class="small">管理</span></th>
            <th class="active">一覧<span class="small">サイト</span></th>
            <th class="active">詳細<span class="small">サイト</span></th>
            <th class="btn-table">操作</th>
          </tr>
        </thead>
        <tbody id="fields-tbody" data-cat="<?= tpcms_h((string)$selectedCatId) ?>">
          <?php if (empty($fields)): ?>
            <tr><td colspan="10">このカテゴリには、まだ項目がありません。</td></tr>
          <?php else: ?>
            <?php foreach ($fields as $f): ?>
              <tr data-id="<?= tpcms_h((string)$f['id']) ?>">
                <td class="handle">☰</td>
                <td class="title"><span class="cell-title"><?= tpcms_h((string)$f['label']) ?></span></td>
                <td class="slug"><?= tpcms_h((string)$f['key']) ?></td>
                <td class="slug"><?= tpcms_h((string)$f['type']) ?></td>
                <td class="active"><?= ((int)$f['searchable'] === 1 ? '◯' : '—') ?></td>
                <td class="active"><?= ((int)$f['list_visible'] === 1 ? '◯' : '—') ?></td>
                <td class="active"><?= ((int)($f['list_site']   ?? 0) === 1 ? '◯' : '—') ?></td>
                <td class="active"><?= ((int)($f['detail_site'] ?? 0) === 1 ? '◯' : '—') ?></td>
                <td class="btn-table">
                  <div class="btns">
                    <a class="btn" href="./fields_edit.php?id=<?= tpcms_h((string)$f['id']) ?>"><img src="assets/pen-solid.svg" alt="編集" title="編集"></a>
                    <form method="post" action="./fields.php" onsubmit="return confirm('この項目を削除します。よろしいですか？（データ入力済みの場合は影響に注意）');">
                    <?= csrf_input_tag() ?>
                      <input type="hidden" name="_action" value="delete">
                      <input type="hidden" name="id" value="<?= tpcms_h((string)$f['id']) ?>">
                      <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>
      </table>
    </div>

  <?php endif; ?>

</div><!-- /#container -->

<script src="./assets/admin.js"></script>

<script>
(function(){
  var type  = document.getElementById('f_type');
  var chk   = document.querySelector('input[name="searchable"]');
  if(!type || !chk) return;
  var label = chk.closest('label');
  var disableOn = ['assets','map_iframe'];

  function update(){
    var ok = disableOn.indexOf(type.value) === -1; // assets / map_iframe 以外はOK
    chk.disabled = !ok;
    if(!ok){ chk.checked = false; }
    if(label){
      label.style.opacity = ok ? '1' : '0.5';
      label.title = ok ? '' : 'この型では「検索」は使えません';
    }
  }
  type.addEventListener('change', update);
  update();
})();
</script>

<script>
(function(){
  const tbody = document.getElementById('fields-tbody');
  if (!tbody) return;

  // 行をドラッグ可能に
  Array.from(tbody.querySelectorAll('td.handle')).forEach(h => {
    h.setAttribute('draggable', 'true');
  });

  let dragging = null;

  tbody.addEventListener('dragstart', (e) => {
    const handle = e.target.closest('.handle');
    const row = e.target.closest('tr');
    if (!handle || !row) {
      e.preventDefault();
      return;
    }
    dragging = row;
    row.classList.add('dragging');
    e.dataTransfer.effectAllowed = 'move';
    // Firefox対策：空でないデータを入れる
    e.dataTransfer.setData('text/plain', row.dataset.id || '');
  });

  tbody.addEventListener('dragend', () => {
    if (dragging) dragging.classList.remove('dragging');
    dragging = null;
  });

  tbody.addEventListener('dragover', (e) => {
    e.preventDefault();
    if (!dragging) return;
    const after = e.target.closest('tr');
    if (!after || after === dragging) return;

    const rect = after.getBoundingClientRect();
    const isAfter = (e.clientY - rect.top) > rect.height / 2;
    if (isAfter) {
      after.after(dragging);
    } else {
      after.before(dragging);
    }
  });

  tbody.addEventListener('drop', async (e) => {
    e.preventDefault();
    if (!dragging) return;

    // 並び結果を収集
    const ids = Array.from(tbody.querySelectorAll('tr'))
      .map(tr => tr.getAttribute('data-id'))
      .filter(Boolean);

    try {
      const fd = new FormData();
      fd.append('_csrf', document.getElementById('csrf_token')?.value || '');
      fd.append('_action', 'sort');
      ids.forEach(id => fd.append('ids[]', id));

      const res = await fetch('./fields.php', { method: 'POST', body: fd, credentials: 'same-origin' });
      if (res.ok) {
        location.reload(); // 再描画して ord を反映
      }
    } catch (err) {
      console.error(err);
    }
  });
})();
</script>

</body>
</html>
