<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/layout/AppRailSidebar.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<!-- Drawer mobile para Layout Rail -->
<script setup>
import { computed, ref, watch, nextTick } from 'vue';
import { useRouter, useRoute } from 'vue-router';

import { useMenuStore } from '@/stores/menuStore';
import { useLayout } from './composables/layout';
import { useEntitlementsStore } from '@/stores/entitlementsStore';
import { useMenuBadges } from '@/composables/useMenuBadges';

import PatientCreatePopover from '@/components/ui/PatientCreatePopover.vue';
import ComponentCadastroRapido from '@/components/ComponentCadastroRapido.vue';

const menuStore = useMenuStore();
const { layoutState, hideMobileMenu } = useLayout();
const entitlements = useEntitlementsStore();
const menuBadges = useMenuBadges();
const router = useRouter();
const route = useRoute();

function menuBadgeLabel(item) {
    const key = item?.badgeKey;
    if (!key) return null;
    const val = menuBadges[key]?.value || 0;
    if (!val) return null;
    return key === 'agendaHoje' ? `${val} hoje` : String(val);
}

const sections = computed(() => {
    const model = menuStore.model || [];
    return model
        .filter((s) => s.label && Array.isArray(s.items) && s.items.length)
        .map((s) => ({
            key: s.label,
            label: s.label,
            icon: s.icon || s.items.find((i) => i.icon)?.icon || 'pi pi-circle',
            items: s.items
        }));
});

// Seções expandidas no accordion
const openSections = ref([]);

// Ao abrir o drawer, expande a seção ativa (ou a primeira)
watch(
    () => layoutState.mobileMenuActive,
    (open) => {
        if (!open) return;
        if (openSections.value.length === 0 && sections.value.length > 0) {
            const activeKey = layoutState.railSectionKey;
            openSections.value = [activeKey || sections.value[0].key];
        }
    }
);

function expandAll() {
    openSections.value = sections.value.map((s) => s.key);
}
function collapseAll() {
    openSections.value = [];
}

// ── Busca ────────────────────────────────────────────────────
const query = ref('');
const showResults = ref(false);
const activeIndex = ref(-1);
const forcedOpen = ref(false);
const searchEl = ref(null);
const searchWrapEl = ref(null);

const RECENT_KEY = 'menu_search_recent';
const recent = ref([]);
function loadRecent() {
    try {
        recent.value = JSON.parse(localStorage.getItem(RECENT_KEY) || '[]');
    } catch {
        recent.value = [];
    }
}
function saveRecent(q) {
    const v = String(q || '').trim();
    if (!v) return;
    const list = [v, ...recent.value.filter((x) => x !== v)].slice(0, 8);
    recent.value = list;
    localStorage.setItem(RECENT_KEY, JSON.stringify(list));
}
function clearRecent() {
    recent.value = [];
    try {
        localStorage.removeItem(RECENT_KEY);
    } catch {}
}
loadRecent();

watch(query, (v) => {
    const hasText = !!v?.trim();
    if (hasText) {
        forcedOpen.value = false;
        showResults.value = true;
        return;
    }
    showResults.value = forcedOpen.value;
});

function clearSearch() {
    query.value = '';
    activeIndex.value = -1;
    showResults.value = false;
    forcedOpen.value = false;
}

function norm(s) {
    return String(s || '')
        .toLowerCase()
        .normalize('NFD')
        .replace(/\p{Diacritic}/gu, '')
        .trim();
}

function isVisibleItem(it) {
    const v = it?.visible;
    if (typeof v === 'function') return !!v();
    if (v === undefined || v === null) return true;
    return v !== false;
}

function flattenMenu(items, trail = []) {
    const out = [];
    for (const it of items || []) {
        if (!isVisibleItem(it)) continue;
        const nextTrail = [...trail, it?.label].filter(Boolean);
        if (it?.to && !it?.items?.length) {
            out.push({ label: it.label || it.to, to: it.to, icon: it.icon, trail: nextTrail, proBadge: !!(it.__showProBadge ?? it.proBadge), feature: it.feature || null });
        }
        if (it?.items?.length) out.push(...flattenMenu(it.items, nextTrail));
    }
    return out;
}

const allLinks = computed(() => flattenMenu(menuStore.model || []));

const results = computed(() => {
    const q = norm(query.value);
    if (!q) return [];
    const wantPro = q === 'pro' || q.startsWith('pro ') || q.includes(' pro');
    return allLinks.value
        .filter((r) => {
            const hay = `${norm(r.label)} ${norm(r.trail.join(' > '))} ${norm(r.to)}`;
            if (hay.includes(q)) return true;
            if (wantPro && (r.proBadge || r.feature)) return true;
            return false;
        })
        .slice(0, 12);
});

watch(results, (list) => {
    activeIndex.value = list.length ? 0 : -1;
});

function escapeHtml(s) {
    return String(s || '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}
function highlight(text, q) {
    const queryNorm = norm(q);
    const raw = String(text || '');
    if (!queryNorm) return escapeHtml(raw);
    const rawNorm = norm(raw);
    const idx = rawNorm.indexOf(queryNorm);
    if (idx < 0) return escapeHtml(raw);
    const before = escapeHtml(raw.slice(0, idx));
    const mid = escapeHtml(raw.slice(idx, idx + queryNorm.length));
    const after = escapeHtml(raw.slice(idx + queryNorm.length));
    return `${before}<mark class="px-1 rounded bg-yellow-200/40">${mid}</mark>${after}`;
}

function onSearchKeydown(e) {
    if (e.key === 'Escape') {
        showResults.value = false;
        forcedOpen.value = false;
        return;
    }
    if (e.key === 'ArrowDown') {
        e.preventDefault();
        if (!results.value.length) return;
        showResults.value = true;
        activeIndex.value = (activeIndex.value + 1) % results.value.length;
        return;
    }
    if (e.key === 'ArrowUp') {
        e.preventDefault();
        if (!results.value.length) return;
        showResults.value = true;
        activeIndex.value = (activeIndex.value - 1 + results.value.length) % results.value.length;
        return;
    }
    if (e.key === 'Enter' && showResults.value && results.value.length && activeIndex.value >= 0) {
        e.preventDefault();
        goToResult(results.value[activeIndex.value]);
    }
}

function onSearchFocus() {
    if (!query.value?.trim()) {
        forcedOpen.value = true;
        showResults.value = true;
    }
}

function applyRecent(q) {
    query.value = q;
    forcedOpen.value = true;
    showResults.value = true;
    activeIndex.value = 0;
    nextTick(() => searchEl.value?.$el?.querySelector?.('input')?.focus?.());
}

async function goToResult(r) {
    saveRecent(query.value);
    query.value = '';
    showResults.value = false;
    activeIndex.value = -1;
    forcedOpen.value = false;
    await router.push(r.to);
    hideMobileMenu();
}

function isSectionOpen(key) {
    return openSections.value.includes(key);
}

function toggleSection(key) {
    const idx = openSections.value.indexOf(key);
    if (idx >= 0) {
        openSections.value.splice(idx, 1);
    } else {
        openSections.value.push(key);
    }
}

function isLocked(item) {
    if (!item.proBadge || !item.feature) return false;
    try {
        return !entitlements.has(item.feature);
    } catch {
        return false;
    }
}

function toPath(to) {
    if (!to) return '';
    if (typeof to === 'string') return to;
    try {
        return router.resolve(to).path || '';
    } catch {
        return '';
    }
}

function isActive(item) {
    const active = String(layoutState.activePath || route.path || '');
    if (!item.to) return false;
    const p = toPath(item.to);
    if (!p) return false;
    if (active === p) return true;
    const segments = p.split('/').filter(Boolean);
    return segments.length >= 2 && active.startsWith(p + '/');
}

function navigate(item) {
    if (isLocked(item)) {
        router.push({ name: 'upgrade', query: { feature: item.feature || '' } });
        hideMobileMenu();
        return;
    }
    if (item.to) {
        layoutState.activePath = toPath(item.to);
        router.push(item.to);
        hideMobileMenu();
    }
}

// Fecha ao navegar
watch(
    () => route.path,
    () => hideMobileMenu()
);

// ── QuickCreate (Pacientes) ───────────────────────────────
const createPopover = ref(null);
const quickDialog = ref(false);

function openQuickCreate(event, item) {
    createPopover.value?.toggle(event);
}
function onQuickCreate() {
    quickDialog.value = true;
}
</script>

<template>
    <Transition name="rs-slide">
        <aside v-if="layoutState.mobileMenuActive" class="rs">
            <!-- Header -->
            <div class="rs__head">
                <span class="rs__brand">Agência PSI</span>
                <button class="rs__close" aria-label="Fechar menu" @click="hideMobileMenu">
                    <i class="pi pi-times" />
                </button>
            </div>

            <!-- Busca + ações -->
            <div ref="searchWrapEl" class="rs__search-area">
                <!-- Campo de busca -->
                <div class="rs__search-field">
                    <div aria-hidden="true" style="position: absolute; left: -9999px; top: -9999px; width: 1px; height: 1px; overflow: hidden">
                        <input type="email" name="email" autocomplete="username" tabindex="-1" disabled />
                        <input type="password" name="password" autocomplete="current-password" tabindex="-1" disabled />
                    </div>

                    <FloatLabel variant="on" class="w-full">
                        <IconField class="w-full">
                            <InputIcon class="pi pi-search" />
                            <!-- type="text" (não "search"): vide AppMenu.vue —
                                 o "search" nativo dá um X de clear próprio que
                                 duplica o botão custom abaixo. -->
                            <InputText
                                ref="searchEl"
                                id="rs_menu_search"
                                name="rs_menu_search"
                                type="text"
                                inputmode="search"
                                autocomplete="off"
                                autocapitalize="off"
                                autocorrect="off"
                                spellcheck="false"
                                data-lpignore="true"
                                data-1p-ignore="true"
                                v-model="query"
                                class="w-full pr-8"
                                variant="filled"
                                @focus="onSearchFocus"
                                @keydown="onSearchKeydown"
                            />
                        </IconField>
                        <label for="rs_menu_search">Encontrar menu...</label>
                    </FloatLabel>

                    <button v-if="query.trim()" type="button" class="rs__search-clear" @mousedown.prevent="clearSearch" aria-label="Limpar busca">
                        <i class="pi pi-times" />
                    </button>
                </div>

                <!-- Dropdown de resultados recentes -->
                <div v-if="showResults && !query.trim() && recent.length" class="rs__dropdown">
                    <div class="rs__dropdown-header">
                        <span>Recentes</span>
                        <button type="button" class="rs__dropdown-action" @mousedown.prevent="clearRecent" aria-label="Limpar recentes">
                            <i class="pi pi-trash" />
                        </button>
                    </div>
                    <button v-for="q in recent" :key="q" class="rs__dropdown-item" type="button" @click.stop.prevent="applyRecent(q)">
                        <i class="pi pi-history rs__dropdown-item-icon" />
                        <span class="flex-1">{{ q }}</span>
                    </button>
                </div>

                <!-- Dropdown de resultados de busca -->
                <div v-else-if="showResults && results.length" class="rs__dropdown">
                    <button v-for="(r, i) in results" :key="String(r.to)" type="button" @mousedown.prevent="goToResult(r)" :class="['rs__dropdown-item', i === activeIndex ? 'rs__dropdown-item--active' : '']">
                        <i v-if="r.icon" :class="r.icon" class="rs__dropdown-item-icon" />
                        <div class="flex flex-col flex-1">
                            <span class="rs__dropdown-item-label" v-html="highlight(r.label, query)" />
                            <small class="rs__dropdown-item-trail">{{ r.trail.join(' > ') }}</small>
                        </div>
                        <span v-if="r.proBadge" class="rs__pro">PRO</span>
                    </button>
                </div>

                <div v-else-if="showResults && query && !results.length" class="rs__no-results">Nenhum item encontrado.</div>

                <!-- Botões expandir/contrair -->
                <div class="rs__actions">
                    <button class="rs__action-btn" type="button" @click="expandAll">
                        <i class="pi pi-chevron-down" />
                        <span>Expandir tudo</span>
                    </button>
                    <button class="rs__action-btn" type="button" @click="collapseAll">
                        <i class="pi pi-chevron-up" />
                        <span>Contrair tudo</span>
                    </button>
                </div>
            </div>

            <!-- Nav -->
            <nav class="rs__nav">
                <template v-for="section in sections" :key="section.key">
                    <!-- Cabeçalho da seção -->
                    <button class="rs__sec" :class="{ 'rs__sec--open': isSectionOpen(section.key) }" @click="toggleSection(section.key)">
                        <i :class="section.icon" class="rs__sec-icon" />
                        <span class="rs__sec-label">{{ section.label }}</span>
                        <i class="pi pi-chevron-down rs__sec-arrow" />
                    </button>

                    <!-- Items da seção -->
                    <div v-show="isSectionOpen(section.key)" class="rs__items">
                        <template v-for="item in section.items" :key="item.to || item.label">
                            <!-- Sub-grupo -->
                            <template v-if="item.items?.length">
                                <div class="rs__group-label">{{ item.label }}</div>
                                <button
                                    v-for="child in item.items"
                                    :key="child.to || child.label"
                                    class="rs__item"
                                    :class="{
                                        'rs__item--active': isActive(child),
                                        'rs__item--locked': isLocked(child)
                                    }"
                                    @click="navigate(child)"
                                >
                                    <i v-if="child.icon" :class="child.icon" class="rs__item-icon" />
                                    <span>{{ child.label }}</span>
                                    <span v-if="isLocked(child)" class="rs__pro">PRO</span>
                                    <span v-if="menuBadgeLabel(child)" class="rs__badge">{{ menuBadgeLabel(child) }}</span>
                                </button>
                            </template>

                            <!-- Item folha -->
                            <div v-else class="flex items-center gap-1">
                                <button
                                    class="rs__item flex-1"
                                    :class="{
                                        'rs__item--active': isActive(item),
                                        'rs__item--locked': isLocked(item)
                                    }"
                                    @click="navigate(item)"
                                >
                                    <i v-if="item.icon" :class="item.icon" class="rs__item-icon" />
                                    <span>{{ item.label }}</span>
                                    <span v-if="isLocked(item)" class="rs__pro">PRO</span>
                                    <span v-if="menuBadgeLabel(item)" class="rs__badge">{{ menuBadgeLabel(item) }}</span>
                                </button>
                                <button v-if="item.quickCreate" class="rs__quick-add" @click.stop="openQuickCreate($event, item)" title="Novo paciente">
                                    <i class="pi pi-plus" />
                                </button>
                            </div>
                        </template>
                    </div>
                </template>
            </nav>

            <!-- PatientCreatePopover (shared) -->
            <PatientCreatePopover ref="createPopover" @quick-create="onQuickCreate" />

            <!-- Cadastro Rápido Dialog -->
            <ComponentCadastroRapido
                v-model="quickDialog"
                title="Cadastro Rápido"
                table-name="patients"
                name-field="nome_completo"
                email-field="email_principal"
                phone-field="telefone"
                :extra-payload="{ status: 'Ativo' }"
                @created="quickDialog = false"
            />
        </aside>
    </Transition>
</template>

<style scoped>
.rs {
    position: fixed;
    top: 0;
    left: 0;
    width: 280px;
    height: 100vh;
    z-index: 99; /* acima do overlay (98), abaixo da topbar (100) quando necessário */
    background: var(--surface-card);
    border-right: 1px solid var(--surface-border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* ── Header ──────────────────────────────────────────────── */
.rs__head {
    height: 56px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 16px;
    border-bottom: 1px solid var(--surface-border);
}
.rs__brand {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--text-color);
}
.rs__close {
    width: 28px;
    height: 28px;
    border-radius: 7px;
    border: none;
    background: transparent;
    color: var(--text-color-secondary);
    cursor: pointer;
    display: grid;
    place-items: center;
    font-size: 0.75rem;
    transition:
        background 0.15s,
        color 0.15s;
}
.rs__close:hover {
    background: var(--surface-ground);
    color: var(--text-color);
}

/* ── Search area ──────────────────────────────────────────── */
.rs__search-area {
    flex-shrink: 0;
    padding: 10px 12px 0;
    border-bottom: 1px solid var(--surface-border);
}
.rs__search-field {
    position: relative;
}
.rs__search-clear {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    background: transparent;
    border: none;
    cursor: pointer;
    opacity: 0.6;
    color: var(--text-color-secondary);
    font-size: 0.75rem;
    display: grid;
    place-items: center;
    padding: 2px;
}
.rs__search-clear:hover {
    opacity: 1;
}

/* ── Dropdown ─────────────────────────────────────────────── */
.rs__dropdown {
    margin-top: 6px;
    border: 1px solid var(--surface-border);
    border-radius: 10px;
    background: var(--surface-card);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    overflow: hidden;
}
.rs__dropdown-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 12px;
    font-size: 0.72rem;
    opacity: 0.65;
    color: var(--text-color-secondary);
}
.rs__dropdown-action {
    background: transparent;
    border: none;
    cursor: pointer;
    opacity: 0.7;
    color: inherit;
    font-size: 0.72rem;
}
.rs__dropdown-action:hover {
    opacity: 1;
}
.rs__dropdown-item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 12px;
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--text-color);
    font-size: 0.82rem;
    text-align: left;
    transition: background 0.12s;
}
.rs__dropdown-item:hover,
.rs__dropdown-item--active {
    background: var(--surface-hover);
}
.rs__dropdown-item-icon {
    font-size: 0.82rem;
    opacity: 0.7;
    flex-shrink: 0;
}
.rs__dropdown-item-label {
    font-weight: 500;
    line-height: 1.3;
}
.rs__dropdown-item-trail {
    font-size: 0.7rem;
    opacity: 0.6;
}
.rs__no-results {
    padding: 8px 4px;
    font-size: 0.8rem;
    opacity: 0.6;
    color: var(--text-color-secondary);
}

/* ── Botões expandir/contrair ─────────────────────────────── */
.rs__actions {
    display: flex;
    gap: 6px;
    padding: 8px 0 10px;
}
.rs__action-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 5px 8px;
    border-radius: 8px;
    border: 1px solid var(--surface-border);
    background: transparent;
    color: var(--text-color-secondary);
    font-size: 0.75rem;
    font-weight: 500;
    cursor: pointer;
    transition:
        background 0.13s,
        color 0.13s;
}
.rs__action-btn:hover {
    background: var(--surface-ground);
    color: var(--text-color);
}
.rs__action-btn .pi {
    font-size: 0.65rem;
}

.rs__nav {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
    scrollbar-width: thin;
    scrollbar-color: var(--surface-border) transparent;
}

/* ── Section accordion ───────────────────────────────────── */
.rs__sec {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: 9px;
    border: none;
    background: transparent;
    color: var(--text-color);
    cursor: pointer;
    font-size: 0.83rem;
    font-weight: 600;
    text-align: left;
    transition: background 0.13s;
}
.rs__sec:hover {
    background: var(--surface-ground);
}
.rs__sec-icon {
    font-size: 0.9rem;
    color: var(--text-color-secondary);
    flex-shrink: 0;
}
.rs__sec-label {
    flex: 1;
}
.rs__sec-arrow {
    font-size: 0.65rem;
    color: var(--text-color-secondary);
    transition: transform 0.2s;
}
.rs__sec--open .rs__sec-arrow {
    transform: rotate(180deg);
}

/* ── Items container ─────────────────────────────────────── */
.rs__items {
    padding-left: 10px;
    padding-bottom: 4px;
}
.rs__group-label {
    font-size: 0.62rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-color-secondary);
    opacity: 0.55;
    padding: 8px 10px 4px;
}
.rs__item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 10px;
    border-radius: 8px;
    border: none;
    background: transparent;
    color: var(--text-color-secondary);
    cursor: pointer;
    font-size: 0.82rem;
    font-weight: 500;
    text-align: left;
    transition:
        background 0.13s,
        color 0.13s;
}
.rs__item:hover {
    background: var(--surface-ground);
    color: var(--text-color);
}
.rs__item--active {
    background: color-mix(in srgb, var(--primary-color) 10%, transparent);
    color: var(--primary-color);
    font-weight: 600;
}
.rs__item--locked {
    opacity: 0.55;
}
.rs__item-icon {
    font-size: 0.82rem;
    flex-shrink: 0;
    opacity: 0.75;
}
.rs__pro {
    font-size: 0.58rem;
    font-weight: 800;
    text-transform: uppercase;
    padding: 1px 5px;
    border-radius: 4px;
    border: 1px solid var(--surface-border);
    color: var(--text-color-secondary);
}
.rs__badge {
    font-size: 0.62rem;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--primary-color);
    color: #fff;
    line-height: 1;
}
.rs__quick-add {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: var(--text-color-secondary);
    cursor: pointer;
    display: grid;
    place-items: center;
    font-size: 0.7rem;
    transition:
        background 0.13s,
        color 0.13s;
}
.rs__quick-add:hover {
    background: var(--surface-ground);
    color: var(--text-color);
}

/* ── Slide-in da esquerda ────────────────────────────────── */
.rs-slide-enter-active,
.rs-slide-leave-active {
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}
.rs-slide-enter-from,
.rs-slide-leave-to {
    transform: translateX(-100%);
}
</style>
