{% extends "core/base.html" %}
{% load static %}

{% block title_text %}Game Sign{% endblock title_text %}
{% block header_text %}<span>Game</span><span>Sign</span>{% endblock header_text %}

{% block content %}
{# Two-phase picker. Landing renders the DRY table hex (1-chair) w. a    #}
{# central SCAN SIGN btn; the stage frame above previews the user's      #}
{# saved sig if any. Clicking SCAN SIGN swaps to picker phase: the hex   #}
{# hides, the card grid appears below the stage. Selection is a two-step #}
{# click on the thumbnail itself (matching room sig-select): click thumb #}
{# → OK btn appears; click OK → lock (stat block + FLIP + SAVE SIGN     #}
{# enable + NVM appears for deselect).                                   #}
{# "Significator" is preserved at the storage layer (User.significator); #}
{# this billboard surface re-brands to "Sign".                           #}
<div class="my-sign-page"
     data-phase="landing"
     data-save-url="{% url 'billboard:save_sign' %}"
     {% if current_significator %}data-current-card-id="{{ current_significator.id }}"{% endif %}
     data-current-reversed="{{ current_significator_reversed|yesno:'true,false' }}"
     data-deck-polarized="{{ request.user.equipped_deck.is_polarized|yesno:'true,false' }}"
     data-polarity="{% if current_significator_reversed %}levity{% else %}gravity{% endif %}">

    {# Stage frame — always reserved at the top of the page; SAVE SIGN +  #}
    {# NVM ride along to its right (sig-select-style). The stage card     #}
    {# itself starts hidden + appears on hover/preview or saved-sig       #}
    {# preview; .sig-stage--frozen is added on OK confirm + cleared by    #}
    {# NVM. data-polarity lives on .my-sign-page so descendant .sig-card  #}
    {# / .sig-stage-card both pick up polarity-themed CSS rules.          #}
    <div class="sig-stage my-sign-stage">
        <div class="sig-stage-card" style="display:none"
             {% if current_significator %}data-card-id="{{ current_significator.id }}"{% endif %}>
            {# Image-mode slot — populated by stage-card.js when the focused #}
            {# card's data-image-url is non-empty (image-equipped deck per   #}
            {# DeckVariant.has_card_images). Hidden by default; CSS shows it #}
            {# when .sig-stage-card carries .sig-stage-card--image.          #}
            <img class="sig-stage-card-img" alt="" style="display:none">
            {# Sprint A.5 — for non-polarized image-equipped decks (Minchiate, #}
            {# future RWS-with-images), the FLIP btn flips the card to its    #}
            {# back instead of cycling polarity (which has no meaning for     #}
            {# non-polarized decks). Pre-rendered back-image element; CSS    #}
            {# toggles visibility via `.sig-stage-card.is-flipped-to-back`.  #}
            {% if request.user.equipped_deck.has_card_images and not request.user.equipped_deck.is_polarized %}
            {# No inline style — `.sig-stage-card-back-img` defaults to       #}
            {# `display: none` via SCSS; `.sig-stage-card.is-flipped-to-back` #}
            {# overrides to `display: block`. Inline would beat the toggle.  #}
            <img class="sig-stage-card-back-img" alt=""
                 src="{{ request.user.equipped_deck.back_image_url }}">
            {% endif %}
            <div class="fan-card-corner fan-card-corner--tl">
                <span class="fan-corner-rank"></span>
                <i class="fa-solid stage-suit-icon" style="display:none"></i>
            </div>
            <div class="fan-card-face">
                <div class="fan-card-face-upright">
                    <p class="fan-card-name-group"></p>
                    <p class="sig-qualifier-above"></p>
                    <p class="fan-card-name"></p>
                    <p class="sig-qualifier-below"></p>
                </div>
                <p class="fan-card-arcana"></p>
                <div class="fan-card-face-reversal">
                    <p class="fan-card-reversal-name"></p>
                    <p class="fan-card-reversal-qualifier"></p>
                </div>
            </div>
            <div class="fan-card-corner fan-card-corner--br">
                <span class="fan-corner-rank"></span>
                <i class="fa-solid stage-suit-icon" style="display:none"></i>
            </div>
        </div>
        {# FLIP — bottom-left of the stage card. Visible only after lock   #}
        {# (.sig-stage--frozen).                                           #}
        <button class="btn btn-reveal my-sign-flip-btn" type="button">FLIP</button>
        <div class="sig-stat-block">
            <button class="btn btn-reverse spin-btn" type="button">SPIN</button>
            <button class="btn btn-info fyi-btn" type="button">FYI</button>
            {# Sprint A.7-polish-3 — stat-block info per [[project-image-based-  #}
            {# deck-face-rendering]]'s locked Q3 spec: underlined Emanation /   #}
            {# Reversal label + title + arcana + keywords. Title color keyed   #}
            {# off `data-arcana-key` on the stage card via parent selector;    #}
            {# `.stat-face-title` + `.stat-face-arcana` empty by default,      #}
            {# populated by stage-card.js `populateStatBlock` from the card    #}
            {# data flow on focus / save.                                       #}
            {# Sprint A.7.5 — `.stat-face-header` wraps the new top-left      #}
            {# rank+suit chip inline w. the underlined EMANATION/REVERSAL    #}
            {# label per [[project-image-based-deck-face-rendering]]'s A.3    #}
            {# Q3 spec. Chip elements empty by default; stage-card.js's      #}
            {# populateStatExtras fills `.stat-chip-rank` + `.stat-chip-icon`.#}
            <div class="stat-face stat-face--upright">
                <div class="stat-face-header">
                    <span class="stat-chip-rank"></span>
                    <div class="stat-chip-tag">
                        <i class="fa-solid stat-chip-icon" style="display:none"></i>
                        <p class="stat-face-label">Emanation</p>
                    </div>
                </div>
                <p class="stat-face-title"></p>
                <p class="stat-face-arcana"></p>
                <ul class="stat-keywords"></ul>
            </div>
            <div class="stat-face stat-face--reversed">
                <div class="stat-face-header">
                    <span class="stat-chip-rank"></span>
                    <div class="stat-chip-tag">
                        <i class="fa-solid stat-chip-icon" style="display:none"></i>
                        <p class="stat-face-label">Reversal</p>
                    </div>
                </div>
                <p class="stat-face-title"></p>
                <p class="stat-face-arcana"></p>
                <ul class="stat-keywords"></ul>
            </div>
            {% include "apps/gameboard/_partials/_sig_fyi_panel.html" with panel_id="id_my_sign_fyi_panel" %}
        </div>
        {# SAVE SIGN + NVM form lives inside the stage so the layout       #}
        {# matches the room's sig-select: btn sits adjacent to the stat    #}
        {# block. Disabled until a card is OK-confirmed.                   #}
        <form id="id_save_sign_form" method="POST" action="{% url 'billboard:save_sign' %}">
            {% csrf_token %}
            <input type="hidden" name="card_id" id="id_save_sign_card_id" value="{{ current_significator.id|default:'' }}">
            <input type="hidden" name="reversed" id="id_save_sign_reversed" value="{{ current_significator_reversed|yesno:'1,0' }}">
            <button type="submit" id="id_save_sign_btn" class="btn btn-primary"{% if not current_significator %} disabled{% endif %}>SAVE SIGN</button>
        </form>
    </div>

    {# Landing phase — DRY table hex w. a single chair + central SCAN     #}
    {# SIGN btn. Reuses the room's hex shell (.room-shell > .room-table   #}
    {# > .room-table-scene > .table-hex-border > .table-hex >             #}
    {# .table-center) + room.js's scaleTable() for viewport-fluid sizing. #}
    <div class="my-sign-landing">
        {# Hex + chair only when the user has no saved sig — once a sig is    #}
        {# locked in, the stage-card preview + stat block above are the page  #}
        {# content; the user must DEL their saved sig before drawing a new   #}
        {# one. SCAN SIGN has no meaning while a sig is committed.            #}
        {% if not current_significator %}
        <div class="room-shell">
            <div id="id_game_table" class="room-table">
                <div class="room-table-scene">
                    <div class="table-hex-border">
                        <div class="table-hex">
                            <div class="table-center">
                                <button id="id_scan_sign_btn" type="button" class="btn btn-primary">SCAN<br>SIGN</button>
                            </div>
                        </div>
                    </div>
                    {# Single founder chair — solo-coded but extensible to the   #}
                    {# 6-chair friend-invite plan in [[project-my-sea-roadmap]]. #}
                    <div class="table-seat" data-slot="1" data-role="PC">
                        <i class="fa-solid fa-chair"></i>
                    </div>
                </div>
            </div>
        </div>
        {% endif %}
        {# CLEAR SIGN — only when a sig is already saved. POST to clear_sign  #}
        {# wipes User.significator + significator_reversed + reloads back to  #}
        {# the no-sig landing. Sprint 4b-adjacent.                             #}
        {% if current_significator %}
        <form id="id_clear_sign_form" class="my-sign-clear-form" method="POST" action="{% url 'billboard:clear_sign' %}">
            {% csrf_token %}
            <button type="submit" id="id_clear_sign_btn" class="btn btn-danger">DEL</button>
        </form>
        {% endif %}
    </div>

    {# Picker phase — card grid, hidden until SCAN SIGN click. Each       #}
    {# .sig-card gets .sig-card-actions w. OK + NVM buttons (CSS gates    #}
    {# visibility via .sig-focused → OK / .sig-reserved--own → NVM).      #}
    <div class="sig-deck-grid my-sign-deck-grid" style="display:none">
        {% for card in cards %}
            <div class="sig-card"
                 data-card-id="{{ card.id }}"
                 data-suit-icon="{{ card.suit_icon }}"
                 data-corner-rank="{{ card.corner_rank }}"
                 data-name-group="{{ card.name_group }}"
                 data-name-title="{{ card.name_title }}"
                 data-arcana="{{ card.get_arcana_display }}"
                 data-arcana-key="{{ card.arcana }}"
                 data-image-url="{{ card.image_url }}"
                 data-correspondence="{{ card.correspondence|default:'' }}"
                 data-keywords-upright="{{ card.keywords_upright|join:',' }}"
                 data-keywords-reversed="{{ card.keywords_reversed|join:',' }}"
                 data-energies="{{ card.energies_json }}"
                 data-operations="{{ card.operations_json }}"
                 data-levity-qualifier="{{ card.levity_qualifier }}"
                 data-gravity-qualifier="{{ card.gravity_qualifier }}"
                 data-reversal-qualifier="{{ card.reversal_qualifier }}"
                 data-reversal-drops-qualifier="{{ card.reversal_drops_qualifier|yesno:'true,false' }}"
                 data-levity-emanation="{{ card.levity_emanation }}"
                 data-gravity-emanation="{{ card.gravity_emanation }}"
                 data-levity-reversal="{{ card.levity_reversal }}"
                 data-gravity-reversal="{{ card.gravity_reversal }}"
                 data-italic-word="{{ card.italic_word }}">
                <div class="fan-card-corner fan-card-corner--tl">
                    <span class="fan-corner-rank">{{ card.corner_rank }}</span>
                    {% if card.suit_icon %}<i class="fa-solid {{ card.suit_icon }}"></i>{% endif %}
                </div>
                <div class="sig-card-actions">
                    <button class="sig-ok-btn btn btn-confirm" type="button">OK</button>
                    <button class="sig-nvm-btn btn btn-cancel" type="button">NVM</button>
                </div>
            </div>
        {% endfor %}
    </div>

    {# Picker JS — phase swap (landing → picker), hover preview, two-step #}
    {# OK/NVM-on-thumbnail selection cycle, FLIP polarity animation lifted #}
    {# from game-kit.js's _flipActive, SPIN orientation toggle. data-     #}
    {# polarity moved to the page wrapper so descendant .sig-card +       #}
    {# .sig-stage-card both pick up the polarity-themed CSS rules.        #}
    <script src="{% static 'apps/epic/stage-card.js' %}"></script>
    <script src="{% static 'apps/epic/room.js' %}"></script>
    <script>
    (function () {
        var pageEl      = document.querySelector('.my-sign-page');
        if (!pageEl) return;
        var landing    = pageEl.querySelector('.my-sign-landing');
        var grid       = pageEl.querySelector('.my-sign-deck-grid');
        var stage      = pageEl.querySelector('.my-sign-stage');
        var stageCard  = stage.querySelector('.sig-stage-card');
        var statBlock  = stage.querySelector('.sig-stat-block');
        var scanBtn    = document.getElementById('id_scan_sign_btn');
        var cardIdInput= document.getElementById('id_save_sign_card_id');
        var saveBtn    = document.getElementById('id_save_sign_btn');
        var spinBtn    = stage.querySelector('.spin-btn');
        var flipBtn    = stage.querySelector('.my-sign-flip-btn');
        var fyiBtn     = stage.querySelector('.fyi-btn');
        var fyiPanel   = stage.querySelector('.sig-info');
        var fyiPrev    = stage.querySelector('.fyi-prev');
        var fyiNext    = stage.querySelector('.fyi-next');
        var revInput   = document.getElementById('id_save_sign_reversed');
        var _currentCard = null;
        var _focusedCardEl = null;
        var _locked = false;
        var _fyiData = [];
        var _fyiIdx = 0;

        function _polarity() {
            return revInput.value === '1' ? 'levity' : 'gravity';
        }

        function _populateStage(cardEl) {
            _focusedCardEl = cardEl;
            _currentCard = StageCard.fromDataset(cardEl);
            StageCard.populateCard(stageCard, _currentCard, _polarity());
            StageCard.populateKeywords(statBlock,
                _currentCard.keywords_upright, _currentCard.keywords_reversed);
            StageCard.populateStatExtras(statBlock, _currentCard);
            _fyiData = StageCard.buildInfoData(_currentCard);
            _fyiIdx = 0;
            if (fyiPanel) StageCard.renderFyi(fyiPanel, _fyiData, _fyiIdx);
            stageCard.style.display = '';
            stageCard.setAttribute('data-card-id', cardEl.dataset.cardId);
        }

        function _clearStage() {
            stageCard.style.display = 'none';
            stageCard.removeAttribute('data-card-id');
            _focusedCardEl = null;
            _currentCard = null;
        }

        function _focus(cardEl) {
            // Click 1 — adds .sig-focused (CSS reveals OK btn) + previews
            // the card on the stage. Stage stays unlocked; another click on
            // a different thumb just moves the focus.
            grid.querySelectorAll('.sig-card.sig-focused').forEach(function (c) {
                if (c !== cardEl) c.classList.remove('sig-focused');
            });
            cardEl.classList.add('sig-focused');
            _populateStage(cardEl);
        }

        function _lock(cardEl) {
            // Click 2 (OK btn) — lock state. Adds .sig-reserved--own to the
            // thumbnail (CSS swaps OK→NVM), .sig-stage--frozen to the stage
            // (CSS reveals stat block + FLIP), enables SAVE SIGN.
            _locked = true;
            _focus(cardEl);
            cardEl.classList.add('sig-reserved--own');
            stage.classList.add('sig-stage--frozen');
            statBlock.classList.remove('fyi-open');
            cardIdInput.value = cardEl.dataset.cardId;
            saveBtn.removeAttribute('disabled');
        }

        function _unlock() {
            // NVM btn — clears lock + focus + stage. SAVE SIGN disables.
            _locked = false;
            stage.classList.remove('sig-stage--frozen');
            statBlock.classList.remove('fyi-open');
            grid.querySelectorAll('.sig-card.sig-reserved--own').forEach(function (c) {
                c.classList.remove('sig-reserved--own');
            });
            grid.querySelectorAll('.sig-card.sig-focused').forEach(function (c) {
                c.classList.remove('sig-focused');
            });
            _clearStage();
            cardIdInput.value = '';
            saveBtn.setAttribute('disabled', 'disabled');
        }

        function _enterPickerPhase() {
            pageEl.setAttribute('data-phase', 'picker');
            if (landing) landing.style.display = 'none';
            if (grid) grid.style.display = '';
        }

        // SCAN SIGN — landing → picker phase swap
        if (scanBtn) {
            scanBtn.addEventListener('click', function () {
                _enterPickerPhase();
            });
        }

        // FLIP — horizontal-perspective polarity flip animation lifted
        // from game-kit.js's _flipActive (500ms Y-axis rotation; offset
        // 0.5 mid-animation swap so the new face renders at the second
        // half-rotation). Preserves SPIN orientation (.stage-card--reversed)
        // through the flip by including its rotate(180deg) in both keyframes.
        function _flipPolarityAnimated() {
            if (!stageCard || stageCard.dataset.flipping) return;
            stageCard.dataset.flipping = '1';
            var spin = stageCard.classList.contains('stage-card--reversed')
                ? ' rotate(180deg)' : '';
            var rest = 'translateX(0px) rotateY(0deg) scale(1)' + spin;
            var mid  = 'translateX(0px) rotateY(0deg) scale(1)' + spin
                     + ' rotateY(90deg)';
            stageCard.animate([
                { transform: rest },
                { transform: mid, offset: 0.5 },
                { transform: rest },
            ], { duration: 500, easing: 'ease' });
            setTimeout(function () {
                revInput.value = revInput.value === '1' ? '0' : '1';
                pageEl.setAttribute('data-polarity', _polarity());
                if (flipBtn) flipBtn.classList.toggle(
                    'is-reversed', revInput.value === '1');
                if (_currentCard && window.StageCard) {
                    StageCard.populateCard(stageCard, _currentCard, _polarity());
                }
            }, 250);
            setTimeout(function () { delete stageCard.dataset.flipping; }, 500);
        }

        // SPIN — 180° rotation + stat-block face swap (preview-only)
        function _toggleOrientation() {
            var on = !stageCard.classList.contains('stage-card--reversed');
            stageCard.classList.toggle('stage-card--reversed', on);
            statBlock.classList.toggle('is-reversed', on);
            if (spinBtn) spinBtn.classList.toggle('is-reversed', on);
        }

        // Grid hover preview (only when nothing is locked)
        if (grid) {
            grid.addEventListener('mouseover', function (e) {
                if (_locked) return;
                var cardEl = e.target.closest('.sig-card');
                if (!cardEl || !window.StageCard) return;
                _populateStage(cardEl);
            });
            grid.addEventListener('mouseout', function (e) {
                if (_locked) return;
                var cardEl = e.target.closest('.sig-card');
                if (!cardEl) return;
                var nextCard = e.relatedTarget && e.relatedTarget.closest
                    && e.relatedTarget.closest('.sig-card');
                if (nextCard) return;
                _clearStage();
            });

            // Click delegation — OK / NVM / card body
            grid.addEventListener('click', function (e) {
                if (e.target.closest('.sig-ok-btn')) {
                    if (_locked) return;
                    var card = e.target.closest('.sig-card');
                    if (card) _lock(card);
                    return;
                }
                if (e.target.closest('.sig-nvm-btn')) {
                    _unlock();
                    return;
                }
                if (_locked) return;  // locked — must NVM first
                var card = e.target.closest('.sig-card');
                if (!card || !window.StageCard) return;
                _focus(card);
            });
        }

        // Sprint A.5 — non-polarized FLIP animation. Mirrors the polarized
        // `_flipPolarityAnimated` shape (rotateY-90 mid-spin + dataset.flipping
        // for the duration so SCSS can hide the btn) but swaps a class
        // toggle for the polarity revInput-flip at the halfway point.
        function _flipToBackAnimated() {
            if (!stageCard || stageCard.dataset.flipping) return;
            stageCard.dataset.flipping = '1';
            var rest = 'translateX(0px) rotateY(0deg) scale(1)';
            var mid  = 'translateX(0px) rotateY(90deg) scale(1)';
            stageCard.animate([
                { transform: rest },
                { transform: mid, offset: 0.5 },
                { transform: rest },
            ], { duration: 500, easing: 'ease' });
            setTimeout(function () {
                stageCard.classList.toggle('is-flipped-to-back');
                if (flipBtn) flipBtn.classList.toggle(
                    'is-reversed',
                    stageCard.classList.contains('is-flipped-to-back')
                );
            }, 250);
            setTimeout(function () { delete stageCard.dataset.flipping; }, 500);
        }

        if (flipBtn) {
            flipBtn.addEventListener('click', function () {
                if (!_currentCard) return;
                // Non-polarized decks (Minchiate, RWS): FLIP shows the deck
                // card-back; stat block stays unchanged — user spec 2026-05-25 PM.
                // Polarized decks (Earthman) keep the existing polarity cycle.
                if (pageEl.dataset.deckPolarized === 'false') {
                    _flipToBackAnimated();
                } else {
                    _flipPolarityAnimated();
                }
            });
        }
        if (spinBtn) {
            spinBtn.addEventListener('click', function () {
                _toggleOrientation();
            });
        }
        if (fyiBtn) {
            fyiBtn.addEventListener('click', function () {
                if (!_currentCard) return;
                statBlock.classList.toggle('fyi-open');
            });
        }
        if (fyiPanel) {
            fyiPanel.addEventListener('click', function () {
                statBlock.classList.remove('fyi-open');
            });
        }
        if (fyiPrev) {
            fyiPrev.addEventListener('click', function () {
                if (!_fyiData.length) return;
                _fyiIdx = (_fyiIdx - 1 + _fyiData.length) % _fyiData.length;
                StageCard.renderFyi(fyiPanel, _fyiData, _fyiIdx);
            });
        }
        if (fyiNext) {
            fyiNext.addEventListener('click', function () {
                if (!_fyiData.length) return;
                _fyiIdx = (_fyiIdx + 1) % _fyiData.length;
                StageCard.renderFyi(fyiPanel, _fyiData, _fyiIdx);
            });
        }

        // On-load: if user has a saved sig, populate the stage preview AND
        // reveal the stat block (via .sig-stage--frozen) so the saved card
        // appears alongside its emanation keywords — the page is read-only
        // on landing while a sig is committed (hex is server-side hidden,
        // DEL is the only action). The picker grid stays hidden until SCAN
        // SIGN — but SCAN SIGN itself is gone in this state, so the user
        // must DEL → reload to ever re-enter picker phase.
        //
        // `significator_reversed` is the POLARITY axis (reversed=True ↔
        // levity), already reflected in `data-polarity` on the page wrapper
        // and threaded into `_polarity()` so `_populateStage` paints the
        // correct levity/gravity qualifier on the upright face. The SPIN
        // axis (.stage-card--reversed rotation) is preview-only and is NOT
        // persisted — saved sigs always render upright in their polarity.
        var savedId = pageEl.dataset.currentCardId;
        if (savedId && grid) {
            var savedCardEl = grid.querySelector(
                '.sig-card[data-card-id="' + savedId + '"]');
            if (savedCardEl) {
                _populateStage(savedCardEl);
                stage.classList.add('sig-stage--frozen');
            }
        }

        // room.js's scaleTable() runs on DOMContentLoaded but at that
        // moment the parent .my-sign-page hasn't flushed its flex sizing,
        // so #id_game_table.clientWidth/Height read 0 and the hex stays
        // unscaled (200×231 inside a 360×320 scene → narrow / elongated).
        // Dispatch a resize on the next tick to re-trigger scaleTable
        // once layout settles.
        window.requestAnimationFrame(function () {
            window.dispatchEvent(new Event('resize'));
        });
    }());
    </script>

    {# Brief intro banner — Default deck warning. See sprint-4a-follow.   #}
    <script src="{% static 'apps/dashboard/note.js' %}"></script>
    {% if show_backup_intro_banner %}
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            if (!window.Brief || !Brief.showBanner) return;
            Brief.showBanner({
                title: 'Default deck warning',
                line_text: 'Look!—no deck is equipped. Navigate to the Game Kit to equip one (FYI) or (NVM) proceed with the Earthman [Shabby Cardstock] deck.',
                post_url: '{% url "gameboard" %}',
                created_at: '',
                kind: 'NUDGE',
            });
            var banner = document.querySelector('.note-banner');
            if (banner) banner.classList.add('my-sign-intro-banner');
        });
    </script>
    {% endif %}
</div>
{% endblock content %}
