<?php

declare(strict_types=1);

/**
 * Public community question page — the question plus its answers, styled as a
 * forum thread. Reached at "/q/{id}/{slug}" via public-routes.php. Read-only +
 * anonymous. Carries per-record SEO meta (reusing config/seo-meta.php) and
 * QAPage JSON-LD so search engines can render a rich result.
 */

require __DIR__ . '/_shell.php';

use PpPhp\Core\Html\Markdown;
use PpPhp\Core\Seo\MetaTags;

$b  = forum_base();
$id = (int) ($GLOBALS['__forum_qid'] ?? ($_GET['id'] ?? 0));
$urlSlug = (string) ($GLOBALS['__forum_slug'] ?? '');

$q = $id > 0 ? dbRow(
    'SELECT q.*, c.name AS cat_name, u.display_name AS author,
            u.username AS author_username, u.reputation AS author_rep, u.email AS author_email
       FROM qa_questions q
       LEFT JOIN qa_categories c ON c.id = q.category_id
       LEFT JOIN qa_users u      ON u.id = q.author_id
      WHERE q.id = ? AND q.deleted_at IS NULL', [$id]
) : null;

if (!$q) {
    http_response_code(404);
    forum_head('Question not found — PPPHP Community');
    echo '<div class="fx-empty"><i class="bi bi-question-circle" style="font-size:34px;opacity:.4"></i>'
       . '<p>That question doesn\'t exist or was removed.</p>'
       . '<p><a class="fx-tag" href="' . $b . '/">← Back to all questions</a></p></div>';
    forum_foot();
    exit;
}

// Canonical slug: 301 a wrong/missing slug to the real one (SEO hygiene).
$canonicalSlug = (string) ($q['slug'] ?? '');
if ($canonicalSlug !== '' && $urlSlug !== $canonicalSlug) {
    header('Location: ' . $b . '/q/' . $id . '/' . rawurlencode($canonicalSlug), true, 301);
    exit;
}

// Count a view once per browser session per question (no inflation on refresh).
if (empty($_SESSION['__fxviews'][$id])) {
    try { \PpPhp\Core\DB::Query('UPDATE qa_questions SET view_count = view_count + 1 WHERE id = ?', [$id]); } catch (\Throwable $e) {}
    $_SESSION['__fxviews'][$id] = 1;
    $q['view_count'] = (int) ($q['view_count'] ?? 0) + 1;
}

$answers = dbAll(
    'SELECT a.*, u.display_name AS author,
            u.username AS author_username, u.reputation AS author_rep, u.email AS author_email
       FROM qa_answers a
       LEFT JOIN qa_users u ON u.id = a.author_id
      WHERE a.question_id = ? AND a.deleted_at IS NULL
      ORDER BY a.is_accepted DESC, a.vote_score DESC, a.created_at ASC', [$id]
);
$tags = dbAll('SELECT t.name FROM qa_question_tags qt JOIN qa_tags t ON t.id = qt.tag_id WHERE qt.question_id = ?', [$id]);

// Related questions (same category or shared tags) — internal linking for SEO.
$related = dbAll(
    "SELECT DISTINCT q2.id, q2.slug, q2.title, q2.answer_count
       FROM qa_questions q2
       LEFT JOIN qa_question_tags qt2 ON qt2.question_id = q2.id
      WHERE q2.id <> ? AND q2.deleted_at IS NULL
        AND (q2.category_id = ? OR qt2.tag_id IN (SELECT tag_id FROM qa_question_tags WHERE question_id = ?))
      ORDER BY q2.vote_score DESC, q2.last_activity_at DESC
      LIMIT 6",
    [$id, (int) ($q['category_id'] ?? 0), $id]
);

// Viewer identity + their existing votes (to render the interactive state).
$viewer   = forum_author_id();
$loggedIn = forum_logged_in();
$isAsker  = ($viewer && (int) $q['author_id'] === $viewer);
$myVotes  = [];
if ($viewer) {
    if (($v = dbValue('SELECT value FROM qa_votes WHERE user_id = ? AND target_type = ? AND target_id = ?', [$viewer, 'question', $id])) !== null) {
        $myVotes['question:' . $id] = (int) $v;
    }
    if ($answers) {
        $aids = array_map(static fn($a) => (int) $a['id'], $answers);
        $ph = implode(',', array_fill(0, count($aids), '?'));
        foreach (dbAll("SELECT target_id, value FROM qa_votes WHERE user_id = ? AND target_type = 'answer' AND target_id IN ($ph)", array_merge([$viewer], $aids)) as $v) {
            $myVotes['answer:' . (int) $v['target_id']] = (int) $v['value'];
        }
    }
}

/** Interactive vote column (up / score / down) + optional trailing markup (accept). */
function fx_votecol(string $type, int $tid, int $score, int $myVote, string $extra = ''): void
{
    echo '<div class="fx-vote" data-type="' . $type . '" data-id="' . $tid . '">'
       . '<button type="button" class="fx-vb up' . ($myVote === 1 ? ' on' : '') . '" data-v="1" aria-label="Upvote"><i class="bi bi-caret-up-fill"></i></button>'
       . '<span class="n">' . $score . '</span>'
       . '<button type="button" class="fx-vb down' . ($myVote === -1 ? ' on' : '') . '" data-v="-1" aria-label="Downvote"><i class="bi bi-caret-down-fill"></i></button>'
       . $extra . '</div>';
}

// ── SEO meta (reuse the build's per-record config) ──
$seoExtra = '';
$seoTitle = forum_e($q['title']) . ' — PPPHP Community';
$seoAll = @include __DIR__ . '/../config/seo-meta.php';
$seoCfg = is_array($seoAll) ? ($seoAll['qa_questions'] ?? []) : [];
$sch = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$base = isset($_SERVER['HTTP_HOST']) ? $sch . '://' . $_SERVER['HTTP_HOST'] . $b : $b;
if ($seoCfg) {
    $res = MetaTags::build($seoCfg, $q, ['base' => $base, 'id' => $id, 'default_title' => $seoTitle]);
    $seoTitle = $res['title'];
    $seoExtra = $res['tags'];
}

// ── QAPage JSON-LD (rich result) ──
$accepted = null;
foreach ($answers as $a) { if ((int) ($a['is_accepted'] ?? 0) === 1) { $accepted = $a; break; } }
$mkAnswer = static function (array $a) use ($base, $id, $canonicalSlug): array {
    return [
        '@type' => 'Answer',
        'text' => forum_excerpt((string) ($a['body_md'] ?? ''), 500),
        'upvoteCount' => (int) ($a['vote_score'] ?? 0),
        'url' => $base . '/q/' . $id . '/' . $canonicalSlug . '#a' . (int) $a['id'],
        'author' => ['@type' => 'Person', 'name' => (string) ($a['author'] ?? 'Anonymous')],
    ];
};
$ld = [
    '@context' => 'https://schema.org',
    '@type' => 'QAPage',
    'mainEntity' => [
        '@type' => 'Question',
        'name' => (string) $q['title'],
        'text' => forum_excerpt((string) ($q['body_md'] ?? ''), 500),
        'answerCount' => count($answers),
        'upvoteCount' => (int) ($q['vote_score'] ?? 0),
        'author' => ['@type' => 'Person', 'name' => (string) ($q['author'] ?? 'Anonymous')],
        'dateCreated' => date('c', strtotime((string) ($q['created_at'] ?? 'now'))),
    ],
];
if ($accepted) { $ld['mainEntity']['acceptedAnswer'] = $mkAnswer($accepted); }
$suggested = array_values(array_filter($answers, static fn($a) => (int) ($a['is_accepted'] ?? 0) !== 1));
if ($suggested) { $ld['mainEntity']['suggestedAnswer'] = array_map($mkAnswer, $suggested); }
$seoExtra .= '<script type="application/ld+json">' . json_encode($ld, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '</script>';

forum_head($seoTitle, $seoExtra);
$ansCount = count($answers);
?>
<a class="fx-back" href="<?= $b ?>/"><i class="bi bi-arrow-left"></i> All questions</a>
<div class="fx-qhead">
  <h1 class="fx-qtitle"><?= forum_e($q['title']) ?></h1>
  <div class="fx-qbar">
    <span><b><?= (int) $q['vote_score'] ?></b> votes</span>
    <span><b><?= (int) $q['answer_count'] ?></b> answers</span>
    <span><b><?= (int) ($q['view_count'] ?? 0) ?></b> views</span>
    <?php if (!empty($q['cat_name'])): ?><span class="fx-cat"><?= forum_e($q['cat_name']) ?></span><?php endif; ?>
    <span style="margin-left:auto"><i class="bi bi-clock"></i> asked <?= forum_e(forum_ago($q['created_at'] ?? null)) ?></span>
  </div>
  <div class="fx-qrow">
    <?php fx_votecol('question', $id, (int) $q['vote_score'], $myVotes['question:' . $id] ?? 0); ?>
    <div class="fx-abody">
      <div class="fx-body"><?= Markdown::toSafeHtml((string) ($q['body_md'] ?? '')) ?></div>
      <div class="fx-meta" style="margin-top:16px">
        <?php if ($tags): ?><span class="fx-tags"><?php foreach ($tags as $t): ?><span class="fx-tag"><?= forum_e($t['name']) ?></span><?php endforeach; ?></span><?php endif; ?>
        <span style="margin-left:auto"><?= forum_userlink($q['author_username'] ?? null, $q['author'] ?? null, (int) ($q['author_rep'] ?? 0), $b, true, $q['author_email'] ?? null) ?></span>
      </div>
    </div>
  </div>
</div>

<h2 class="fx-answers-h"><?= $ansCount ?> Answer<?= $ansCount === 1 ? '' : 's' ?></h2>
<?php foreach ($answers as $a):
    $aid = (int) $a['id'];
    $acc = (int) ($a['is_accepted'] ?? 0) === 1;
    if ($isAsker) {
        $extra = '<button type="button" class="fx-acceptbtn' . ($acc ? ' on' : '') . '" data-id="' . $aid . '" title="' . ($acc ? 'Un-accept' : 'Accept this answer') . '"><i class="bi bi-check-lg"></i></button>';
    } else {
        $extra = $acc ? '<span class="fx-accepted" title="Accepted answer"><i class="bi bi-check-lg"></i></span>' : '';
    }
?>
  <div class="fx-answer <?= $acc ? 'accepted' : '' ?>" id="a<?= $aid ?>">
    <?php fx_votecol('answer', $aid, (int) $a['vote_score'], $myVotes['answer:' . $aid] ?? 0, $extra); ?>
    <div class="fx-abody">
      <?php if ($acc): ?><div style="color:var(--fx-green);font-weight:700;font-size:13px;margin-bottom:8px"><i class="bi bi-check-circle-fill"></i> Accepted answer</div><?php endif; ?>
      <div class="fx-body"><?= Markdown::toSafeHtml((string) ($a['body_md'] ?? '')) ?></div>
      <div class="fx-acredit"><span class="fx-credit"><?= forum_userlink($a['author_username'] ?? null, $a['author'] ?? null, (int) ($a['author_rep'] ?? 0), $b, true, $a['author_email'] ?? null) ?><span class="fx-credit-when">· answered <?= forum_e(forum_ago($a['created_at'] ?? null)) ?></span></span></div>
    </div>
  </div>
<?php endforeach; ?>

<?php if ($loggedIn): ?>
<div class="fx-answerbox" id="answer-form">
  <h3>Your Answer</h3>
  <?php if (($_GET['e'] ?? '') === 'short'): ?><div class="fx-formerr"><i class="bi bi-exclamation-circle"></i> Your answer was too short — please add a little more.</div><?php endif; ?>
  <form method="post" action="<?= $b ?>/forum/answer">
    <input type="hidden" name="_token" value="<?= forum_e(forum_csrf()) ?>">
    <input type="hidden" name="question_id" value="<?= $id ?>">
    <textarea class="fx-textarea" name="body" required placeholder="Write your answer — be clear and helpful. Markdown supported."></textarea>
    <p class="fx-mdhint"><i class="bi bi-markdown"></i> Markdown: **bold**, `code`, - lists, &gt; quotes, [links](url)</p>
    <button class="fx-submit" type="submit" style="margin-top:12px">Post your answer</button>
  </form>
</div>
<?php else: ?>
<div class="fx-cta">
  <div style="font-weight:700">Know the answer?</div>
  <div style="color:var(--fx-muted);font-size:14px">Sign in to post your answer and help the community.</div>
  <a href="<?= $b ?>/login">Sign in to answer</a>
</div>
<?php endif; ?>
<?php if ($related): ?>
<div class="fx-related">
  <h3>Related Questions</h3>
  <?php foreach ($related as $r): ?>
    <a href="<?= $b ?>/q/<?= (int) $r['id'] ?>/<?= forum_e($r['slug']) ?>"><span><?= forum_e($r['title']) ?></span><span class="m"><?= (int) $r['answer_count'] ?> ans</span></a>
  <?php endforeach; ?>
</div>
<?php endif; ?>
<script>
(function () {
  var CSRF = <?= json_encode(forum_csrf()) ?>;
  var BASE = <?= json_encode($b) ?>;
  var LOGGED = <?= $loggedIn ? 'true' : 'false' ?>;
  function toast(m){var t=document.createElement('div');t.className='fx-toast';t.textContent=m;document.body.appendChild(t);requestAnimationFrame(function(){t.classList.add('show');});setTimeout(function(){t.classList.remove('show');setTimeout(function(){t.remove();},260);},2200);}
  function post(d){d._token=CSRF;return fetch(BASE+'/forum/act',{method:'POST',headers:{'X-CSRF-TOKEN':CSRF,'X-Requested-With':'XMLHttpRequest'},body:new URLSearchParams(d)}).then(function(r){return r.json().then(function(j){return{status:r.status,j:j};});});}
  document.querySelectorAll('.fx-vb').forEach(function(btn){
    btn.addEventListener('click',function(){
      if(!LOGGED){window.location.href=BASE+'/login';return;}
      var col=btn.closest('.fx-vote');
      post({act:'vote',type:col.dataset.type,id:col.dataset.id,value:btn.dataset.v}).then(function(res){
        if(res.status===401){window.location.href=BASE+'/login';return;}
        if(!res.j.ok){toast(res.j.message||'Could not register your vote');return;}
        col.querySelector('.n').textContent=res.j.score;
        col.querySelector('.fx-vb.up').classList.toggle('on',res.j.myVote===1);
        col.querySelector('.fx-vb.down').classList.toggle('on',res.j.myVote===-1);
      }).catch(function(){toast('Network error');});
    });
  });
  document.querySelectorAll('.fx-acceptbtn').forEach(function(btn){
    btn.addEventListener('click',function(){
      post({act:'accept',id:btn.dataset.id}).then(function(res){
        if(!res.j.ok){toast(res.j.message||'Could not accept');return;}
        document.querySelectorAll('.fx-answer').forEach(function(a){a.classList.remove('accepted');});
        document.querySelectorAll('.fx-acceptbtn').forEach(function(b){b.classList.remove('on');b.title='Accept this answer';});
        if(res.j.accepted){var el=document.getElementById('a'+res.j.accepted);if(el)el.classList.add('accepted');btn.classList.add('on');btn.title='Un-accept';toast('Answer accepted');}
        else{toast('Acceptance removed');}
      }).catch(function(){toast('Network error');});
    });
  });
})();
</script>
<?php forum_foot(); ?>
