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

import { supabase } from '@/lib/supabase/client';
import { useConversationDrawerStore } from '@/stores/conversationDrawerStore';

const router = useRouter();

// Aliases "semânticos" → resolvidos pra rota real com base no role atual.
// Evita que deeplinks gravados no backend quebrem se o caminho da rota mudar
// ou se o usuário logado pertencer a outro contexto (therapist vs clinic_admin).
const DEEPLINK_ALIASES = {
    '/crm/conversas': { therapist: '/therapist/conversas', clinic_admin: '/admin/conversas' },
    '/conversas': { therapist: '/therapist/conversas', clinic_admin: '/admin/conversas' }
};

function resolveDeeplink(link) {
    if (!link || typeof link !== 'string') return link;
    const alias = DEEPLINK_ALIASES[link];
    if (!alias) return link;
    const role = tenantStore?.activeRole || 'therapist';
    return alias[role] || alias.therapist;
}

function goToDeeplink(link) {
    if (!link) return;
    const resolved = resolveDeeplink(link);
    if (typeof resolved === 'string' && resolved.startsWith('/')) {
        router.push(resolved);
    } else {
        window.location.href = resolved;
    }
}

// Abre o drawer global de conversa a partir do thread_key (do payload do alerta).
// Busca o row da view conversation_threads e delega pro store.
async function openConversationDrawer(threadKey) {
    if (!threadKey) return;
    try {
        const tenantId = tenantStore.activeTenantId;
        const { data, error } = await supabase
            .from('conversation_threads')
            .select('*')
            .eq('tenant_id', tenantId)
            .eq('thread_key', threadKey)
            .maybeSingle();
        if (error) throw error;
        if (!data) {
            // Thread sumiu (foi arquivada ou paciente deletado) — fallback pra lista
            goToDeeplink('/conversas');
            return;
        }
        const drawerStore = useConversationDrawerStore();
        await drawerStore.openForThread(data);
    } catch (e) {
        console.warn('[AppLayout] openConversationDrawer falhou:', e?.message);
        goToDeeplink('/conversas');
    }
}

import AppFooter from './AppFooter.vue';
import AppSidebar from './AppSidebar.vue';
import AppTopbar from './AppTopbar.vue';
import AppRail from './AppRail.vue';
import AppRailPanel from './AppRailPanel.vue';
import AppRailSidebar from './AppRailSidebar.vue';
import AjudaDrawer from '@/components/AjudaDrawer.vue';
import SupportDebugBanner from '@/support/components/SupportDebugBanner.vue';
import GlobalNoticeBanner from '@/features/notices/GlobalNoticeBanner.vue';
import AppThemeBar from './AppThemeBar.vue';
import ConversationDrawer from '@/components/conversations/ConversationDrawer.vue';
import GlobalInboundNotifier from '@/components/conversations/GlobalInboundNotifier.vue';
import { useConfiguratorBar } from './composables/useConfiguratorBar';

const { open: themeBarOpen } = useConfiguratorBar();

import { useNoticeStore } from '@/stores/noticeStore';
import { useTenantStore } from '@/stores/tenantStore';
import { useEntitlementsStore } from '@/stores/entitlementsStore';
import { useTenantFeaturesStore } from '@/stores/tenantFeaturesStore';

import { fetchDocsForPath, useAjuda } from '@/composables/useAjuda';

const { drawerOpen } = useAjuda();

const ajudaPushStyle = computed(() => ({
    transition: 'padding-right 0.3s ease',
    paddingRight: drawerOpen.value ? '420px' : '0'
}));

const route = useRoute();
const noticeStore = useNoticeStore();
const { layoutConfig, layoutState, hideMobileMenu, isDesktop, effectiveVariant, effectiveMenuMode } = useLayout();


const layoutArea = computed(() => route.meta?.area || null);
provide('layoutArea', layoutArea);

const tenantStore = useTenantStore();
const entitlementsStore = useEntitlementsStore();
const tf = useTenantFeaturesStore();

// ── Atualiza contexto dos notices ao mudar de rota ────────────
watch(
    () => route.path,
    (path) => noticeStore.updateContext(path, tenantStore.role),
    { immediate: false }
);

const containerClass = computed(() => {
    return {
        'layout-overlay': effectiveMenuMode.value === 'overlay',
        'layout-static': effectiveMenuMode.value === 'static',
        'layout-overlay-active': layoutState.overlayMenuActive,
        'layout-mobile-active': layoutState.mobileMenuActive,
        'layout-static-inactive': layoutState.staticMenuInactive
    };
});

function getTenantId() {
    return tenantStore.activeTenantId || tenantStore.tenantId || tenantStore.currentTenantId || tenantStore.tenant?.id || null;
}

async function revalidateAfterSessionRefresh() {
    try {
        if (!tenantStore.loaded && !tenantStore.loading) {
            await tenantStore.loadSessionAndTenant();
        }
        const tid = getTenantId();
        if (!tid) return;
        await Promise.allSettled([entitlementsStore.loadForTenant?.(tid, { force: true }), tf.fetchForTenant?.(tid, { force: true })]);
    } catch (e) {
        console.warn('[AppLayout] revalidateAfterSessionRefresh failed:', e?.message || e);
    }
}

function onSessionRefreshed() {
    const p = String(route.path || '');
    const isTenantArea = p.startsWith('/admin') || p.startsWith('/therapist') || p.startsWith('/supervisor') || p.startsWith('/saas');
    if (!isTenantArea) return;
    revalidateAfterSessionRefresh();
}

watch(
    () => route.path,
    (path) => fetchDocsForPath(path),
    { immediate: true }
);

onMounted(() => {
    window.addEventListener('app:session-refreshed', onSessionRefreshed);
    noticeStore.init(tenantStore.role, route.path);
});

onBeforeUnmount(() => {
    window.removeEventListener('app:session-refreshed', onSessionRefreshed);
});
</script>

<template>
    <!-- ══ Fullscreen ══ -->
    <template v-if="route.meta?.fullscreen">
        <router-view />
        <Toast />
    </template>

    <!-- ══ Layout Rail ══ -->
    <template v-else-if="effectiveVariant === 'rail'">
        <div class="l2-root">
            <!-- Rail de ícones: oculto em mobile (≤ xl (1280px)) via CSS -->
            <AppRail />
            <div class="l2-body">
                <AppTopbar />
                <div class="l2-content">
                    <AppRailPanel />
                    <div class="l2-main" :style="ajudaPushStyle">
                        <router-view />
                    </div>
                </div>
            </div>
        </div>
        <!-- Sidebar mobile exclusiva do Rail -->
        <AppRailSidebar />
        <!-- Overlay escuro ao abrir sidebar mobile -->
        <div v-if="layoutState.mobileMenuActive" class="l2-mobile-overlay" @click="hideMobileMenu" />
        <AjudaDrawer />
        <Toast />
    </template>

    <!-- ══ Layout Clássico melhorado ══ -->
    <template v-else>
        <div class="layout-wrapper" :class="containerClass">
            <AppTopbar />
            <AppSidebar />
            <div class="layout-main-container" :style="ajudaPushStyle">
                <div class="layout-main">
                    <router-view />
                </div>
                <AppFooter />
            </div>
            <div class="layout-mask animate-fadein" @click="hideMobileMenu" />
        </div>
        <AjudaDrawer />
        <Toast />
    </template>

    <!-- ══ Barra de tema — persiste em qualquer layout/rota ══ -->
    <Transition name="theme-bar">
        <AppThemeBar v-if="themeBarOpen" />
    </Transition>

    <!-- ══ Global — fora de todos os branches, persiste em qualquer layout/rota ══ -->
    <SupportDebugBanner />
    <GlobalNoticeBanner />
    <ConversationDrawer />
    <GlobalInboundNotifier />

    <!-- Toast especial pra alertas de sistema (heartbeat, saldo baixo, etc) —
         vermelho sticky com botão de ação opcional via payload.deeplink -->
    <Toast group="system-alerts" position="top-right" :pt="{ root: { style: 'width: 28rem; max-width: 92vw' } }">
        <template #message="slotProps">
            <div class="flex flex-col gap-2 w-full">
                <div class="flex items-start gap-2">
                    <i class="pi pi-exclamation-circle text-lg mt-0.5" style="color: var(--p-red-500)" />
                    <div class="flex-1 min-w-0">
                        <div class="font-bold text-sm">{{ slotProps.message.summary }}</div>
                        <div class="text-xs mt-0.5 leading-relaxed opacity-85">{{ slotProps.message.detail }}</div>
                    </div>
                </div>
                <div class="flex gap-2 self-end flex-wrap">
                    <Button
                        v-if="slotProps.message.data?.thread_key"
                        label="Abrir conversa"
                        icon="pi pi-comment"
                        size="small"
                        severity="danger"
                        outlined
                        class="rounded-full"
                        @click="openConversationDrawer(slotProps.message.data.thread_key)"
                    />
                    <Button
                        v-if="slotProps.message.data?.deeplink"
                        :label="slotProps.message.data?.actionLabel || 'Abrir'"
                        icon="pi pi-arrow-right"
                        iconPos="right"
                        size="small"
                        severity="danger"
                        class="rounded-full"
                        @click="goToDeeplink(slotProps.message.data.deeplink)"
                    />
                </div>
            </div>
        </template>
    </Toast>
</template>

<style>
/* ──────────────────────────────────────────────
   LAYOUT CLÁSSICO — ajustes globais (não scoped)
   para sobrescrever o tema PrimeVue
────────────────────────────────────────────── */

/* ── Global Notice Banner: variável de altura ─────────────
   Definida aqui como fallback; o componente altera via JS   */
:root {
    --notice-banner-height: 0px;
}

/* ── Topbar: desce pelo banner ─────────────────────────── */
.rail-topbar {
    top: var(--notice-banner-height) !important;
}

/* ── Sidebar — sempre abaixo da topbar fixed (56px) ────────
   Desce pelo banner também.                                 */
.layout-sidebar {
    position: fixed !important;
    top: calc(56px + var(--notice-banner-height)) !important;
    left: 0 !important;
    height: calc(100vh - 56px - var(--notice-banner-height)) !important;
    border-radius: 0 !important;
    padding: 0 !important;
    box-shadow: 2px 0 6px rgba(0, 0, 0, 0.06) !important;
    border-right: 1px solid var(--surface-border) !important;
    z-index: 999;
}

/* ── Topbar no layout Clássico — sempre tela toda, acima da sidebar */
.layout-wrapper .rail-topbar {
    z-index: 1000 !important;
}

/* ── Conteúdo — margem esquerda por modo ───────────────────
   Static ativo  : afasta da sidebar
   Static inativo: sem margem
   Overlay       : sem margem (sidebar flutua sobre o conteúdo) */
.layout-main-container {
    margin-left: 20rem !important;
    padding-left: 0 !important;
    padding-top: calc(56px + var(--notice-banner-height)) !important;
}
.layout-overlay .layout-main-container,
.layout-static-inactive .layout-main-container {
    margin-left: 0 !important;
}
@media (width <= theme(--breakpoint-xl, 1280px)) {
    .layout-main-container {
        margin-left: 0 !important;
    }
}

/* ── Overlay: hambúrguer sempre visível ─────────────────────
   Em overlay a sidebar não ocupa espaço fixo — o botão precisa
   estar disponível em qualquer largura de tela. */
.layout-overlay .rail-topbar__hamburger {
    display: grid !important;
}

/* ── AppThemeBar — slide-up ao abrir, slide-down ao fechar ───
   A transição está definida no próprio componente (.theme-bar).
   Aqui apenas declaramos o estado inicial (enter) / final (leave). */
.theme-bar-enter-from,
.theme-bar-leave-to {
    transform: translateY(100%);
}
</style>

<style scoped>
/* ─── Layout Rail ─────────────────────────────── */
.l2-root {
    position: fixed;
    top: var(--notice-banner-height, 0px); /* desce pelo banner */
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    overflow: hidden;
    background: var(--surface-ground);
}

.l2-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    padding-top: 56px; /* compensa topbar — banner já absorvido pelo l2-root */
}

.l2-content {
    flex: 1;
    min-height: 0;
    display: flex;
    overflow: hidden;
}

.l2-main {
    flex: 1;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
    --layout-sticky-top: 0px;
}

/* Rail de ícones: oculto em mobile */
@media (width <= theme(--breakpoint-xl, 1280px)) {
    .l2-root :deep(.rail) {
        display: none;
    }
    /* Painel lateral: também oculto em mobile (substituído pelo AppRailSidebar) */
    .l2-content :deep(.rp) {
        display: none;
    }
}

/* Overlay escuro ao abrir sidebar mobile no Rail */
.l2-mobile-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 98;
    animation: fadeIn 0.2s ease;
}
@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}
</style>
