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

import { useToast } from 'primevue/usetoast';

import ModuleRow from '@/features/clinic/components/ModuleRow.vue';

import { useTenantStore } from '@/stores/tenantStore';
import { useTenantFeaturesStore } from '@/stores/tenantFeaturesStore';
import { useMenuStore } from '@/stores/menuStore';

const toast = useToast();
const route = useRoute();

const tenantStore = useTenantStore();
const tf = useTenantFeaturesStore();
const menuStore = useMenuStore();

const savingKey = ref(null);
const applyingPreset = ref(false);

// evita cliques enquanto o contexto inicial ainda tá montando
const booting = ref(true);

// guarda features que o plano bloqueou (pra não ficar "clicando e errando")
const planDenied = ref(new Set());

const tenantId = computed(() => tenantStore.activeTenantId || tenantStore.tenantId || tenantStore.currentTenantId || tenantStore.tenant?.id || null);

const role = computed(() => tenantStore.activeRole || tenantStore.role || null);

// ✅ Somente owners/admins da clínica podem alterar features.
// Terapeutas enxergam a página em modo somente-leitura (sem toggles, sem presets).
const isOwner = computed(() => role.value === 'owner' || role.value === 'admin');

const loading = computed(() => tf.loading || tenantStore.loading || booting.value);

const tenantReady = computed(() => !!tenantId.value && tenantStore.loaded);

function isOn(key) {
    if (!tenantId.value) return false;
    try {
        return !!tf.isEnabled(key, tenantId.value);
    } catch {
        return false;
    }
}

function labelOf(key) {
    if (key === 'patients') return 'Pacientes';
    if (key === 'shared_reception') return 'Recepção / Secretária';
    if (key === 'rooms') return 'Salas / Coworking';
    if (key === 'intake_public') return 'Link externo de cadastro';
    return key;
}

function isPlanDeniedError(e) {
    const msg = String(e?.message || e || '').toLowerCase();
    if (msg.includes('não permitida') && msg.includes('plano')) return true;
    if (msg.includes('fora do plano')) return true;
    if (msg.includes('saas_admin')) return true;
    return false;
}

function markPlanDenied(key, e) {
    if (!key) return;
    if (!isPlanDeniedError(e)) return;
    const s = new Set(planDenied.value);
    s.add(key);
    planDenied.value = s;
}

function clearPlanDenied() {
    planDenied.value = new Set();
}

function isLocked(key) {
    return !isOwner.value || !tenantReady.value || loading.value || applyingPreset.value || !!savingKey.value || planDenied.value.has(key);
}

// ===============================
// 🧠 Menu refresh (debounced)
// evita "menu sumindo" ao resetar durante loading
// ===============================
let menuRefreshT = null;
function requestMenuRefresh() {
    if (menuRefreshT) clearTimeout(menuRefreshT);
    menuRefreshT = setTimeout(() => {
        if (tf.loading || tenantStore.loading || booting.value) {
            return requestMenuRefresh();
        }
        if (typeof menuStore.reset === 'function') menuStore.reset();
    }, 150);
}

/**
 * ✅ Recalcular menu SEM router.replace().
 * O menu some quando o reset acontece enquanto stores ainda carregam.
 */
async function afterFeaturesChanged() {
    if (!tenantId.value) return;

    // ✅ refresh suave (evita "pisca vazio")
    await tf.fetchForTenant(tenantId.value, { force: false });

    // ✅ nunca navegar/replace aqui
    requestMenuRefresh();

    await nextTick();
}

async function reload() {
    if (!tenantId.value) return;
    clearPlanDenied();

    await tf.fetchForTenant(tenantId.value, { force: true });
    requestMenuRefresh();

    toast.add({
        severity: 'info',
        summary: 'Atualizado',
        detail: 'Módulos recarregados.',
        life: 2000
    });
}

async function toggle(key) {
    if (!isOwner.value) {
        toast.add({
            severity: 'warn',
            summary: 'Acesso restrito',
            detail: 'Apenas o administrador da clínica pode alterar módulos.',
            life: 3000
        });
        return;
    }

    if (!tenantId.value) {
        toast.add({
            severity: 'warn',
            summary: 'Sem tenant ativo',
            detail: 'Selecione/ative um tenant primeiro.',
            life: 2500
        });
        return;
    }

    if (planDenied.value.has(key)) {
        toast.add({
            severity: 'warn',
            summary: 'Indisponível no plano',
            detail: `${labelOf(key)} não está disponível no plano atual.`,
            life: 2800
        });
        return;
    }

    if (savingKey.value) return;
    savingKey.value = key;

    try {
        const next = !isOn(key);

        await tf.setForTenant(tenantId.value, key, next);
        await afterFeaturesChanged();

        toast.add({
            severity: 'success',
            summary: 'Atualizado',
            detail: `${labelOf(key)}: ${next ? 'Ativado' : 'Desativado'}`,
            life: 2500
        });
    } catch (e) {
        markPlanDenied(key, e);

        toast.add({
            severity: isPlanDeniedError(e) ? 'warn' : 'error',
            summary: isPlanDeniedError(e) ? 'Bloqueado pelo plano' : 'Erro',
            detail: e?.message || 'Falha ao atualizar módulo',
            life: 3800
        });
    } finally {
        savingKey.value = null;
    }
}

async function applyPreset(preset) {
    if (!isOwner.value) {
        toast.add({
            severity: 'warn',
            summary: 'Acesso restrito',
            detail: 'Apenas o administrador da clínica pode aplicar presets.',
            life: 3000
        });
        return;
    }

    if (!tenantId.value) return;
    if (applyingPreset.value) return;

    clearPlanDenied();
    applyingPreset.value = true;

    try {
        const map = {
            coworking: {
                patients: false,
                shared_reception: false,
                rooms: true,
                intake_public: false
            },
            reception: {
                patients: false,
                shared_reception: true,
                rooms: false,
                intake_public: false
            },
            full: {
                patients: true,
                shared_reception: true,
                rooms: true,
                intake_public: true
            }
        };

        const cfg = map[preset];
        if (!cfg) return;

        for (const [k, v] of Object.entries(cfg)) {
            try {
                await tf.setForTenant(tenantId.value, k, v);
            } catch (e) {
                markPlanDenied(k, e);
                toast.add({
                    severity: isPlanDeniedError(e) ? 'warn' : 'error',
                    summary: isPlanDeniedError(e) ? 'Bloqueado pelo plano' : 'Erro',
                    detail: `${labelOf(k)}: ${e?.message || 'falha ao aplicar'}`,
                    life: 4200
                });
            }
        }

        await afterFeaturesChanged();

        toast.add({
            severity: 'success',
            summary: 'Preset aplicado',
            detail: 'Configuração atualizada.',
            life: 2500
        });
    } catch (e) {
        toast.add({
            severity: 'error',
            summary: 'Erro',
            detail: e?.message || 'Falha ao aplicar preset',
            life: 3500
        });
    } finally {
        applyingPreset.value = false;
    }
}

// Carrega tenant/session se necessário
onMounted(async () => {
    try {
        if (!tenantStore.loaded && !tenantStore.loading) {
            await tenantStore.loadSessionAndTenant();
        }
    } finally {
        // o watch do tenantId fará o fetch; aqui só destrava a tela
        booting.value = false;
    }
});

// Busca features sempre que o tenant ficar disponível (e no mount)
watch(
    () => tenantId.value,
    async (id) => {
        if (!id) return;

        booting.value = true;
        clearPlanDenied();

        try {
            // ✅ não force no mount para evitar "pisca"
            await tf.fetchForTenant(id, { force: false });

            // ✅ reset só quando estiver estável (debounced)
            requestMenuRefresh();

            await nextTick();
        } catch (e) {
            toast.add({
                severity: 'error',
                summary: 'Erro ao carregar módulos',
                detail: e?.message || 'Falha ao buscar tenant_features',
                life: 4000
            });
        } finally {
            booting.value = false;
        }
    },
    { immediate: true }
);

// blindagem: se a rota mudar dentro da área admin e o menu tiver resetado,
// solicita refresh leve (sem navigation)
watch(
    () => route.fullPath,
    async () => {
        requestMenuRefresh();
    }
);
</script>

<template>
    <!-- Sentinel -->
    <div class="h-px" />

    <!-- Hero sticky -->
    <div class="sticky mx-3 md:mx-4 mb-4 z-20 overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5" :style="{ top: 'var(--layout-sticky-top, 56px)' }">
        <div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
            <div class="absolute rounded-full blur-[70px] w-72 h-72 -top-16 -right-20 bg-indigo-400/10" />
            <div class="absolute rounded-full blur-[70px] w-80 h-80 top-10 -left-24 bg-emerald-400/10" />
            <div class="absolute rounded-full blur-[70px] w-72 h-72 -bottom-20 right-24 bg-fuchsia-400/10" />
        </div>

        <div class="relative z-10 flex flex-col gap-2">
            <div class="flex items-center justify-between gap-3 flex-wrap">
                <div class="min-w-0">
                    <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">Tipos de Clínica</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Ative/desative recursos por clínica. Controla menu, rotas e acesso no banco (RLS).</div>
                </div>

                <div class="shrink-0 flex items-center gap-2">
                    <Button label="Recarregar" icon="pi pi-refresh" severity="secondary" outlined :loading="loading" :disabled="applyingPreset || !!savingKey" @click="reload" />
                </div>
            </div>

            <div class="flex flex-wrap items-center gap-2">
                <span class="inline-flex items-center gap-2 rounded-full border border-[var(--surface-border)] px-3 py-1 text-[1rem] text-[var(--text-color-secondary)]">
                    <i class="pi pi-building" />
                    Tenant: <b class="font-mono">{{ tenantId || '�"' }}</b>
                </span>
                <span class="inline-flex items-center gap-2 rounded-full border border-[var(--surface-border)] px-3 py-1 text-[1rem] text-[var(--text-color-secondary)]">
                    <i class="pi pi-user" />
                    Role: <b>{{ role || '�"' }}</b>
                </span>
                <span v-if="!tenantReady" class="inline-flex items-center gap-2 rounded-full border border-[var(--surface-border)] px-3 py-1 text-[1rem] text-[var(--text-color-secondary)] opacity-70">
                    <i class="pi pi-spin pi-spinner" />
                    Carregando contexto…
                </span>
                <span v-else-if="loading" class="inline-flex items-center gap-2 rounded-full border border-[var(--surface-border)] px-3 py-1 text-[1rem] text-[var(--text-color-secondary)] opacity-70">
                    <i class="pi pi-spin pi-spinner" />
                    Atualizando módulos…
                </span>
            </div>
        </div>
    </div>

    <div class="px-3 md:px-4 pb-8 flex flex-col gap-4">
        <!-- Banner: somente leitura -->
        <div v-if="!isOwner && tenantReady" class="flex items-center gap-3 rounded-md border border-amber-400/40 bg-amber-400/10 px-5 py-4 text-[1rem]">
            <i class="pi pi-lock text-amber-400 shrink-0" />
            <span class="text-[1rem] text-[var(--text-color)] opacity-90"> Você está visualizando as configurações da clínica em <b>modo somente leitura</b>. Apenas o administrador pode ativar ou desativar módulos. </span>
        </div>

        <!-- Presets -->
        <div class="grid grid-cols-1 md:grid-cols-3 gap-3">
            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
                <div class="flex items-start justify-between gap-3">
                    <div class="min-w-0">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">Preset: Coworking</div>
                        <div class="mt-1 text-[1rem] text-[var(--text-color-secondary)]">Para aluguel de salas: sem pacientes, com salas.</div>
                    </div>
                    <Button size="small" label="Aplicar" severity="secondary" outlined :loading="applyingPreset" :disabled="!isOwner || !tenantReady || loading || !!savingKey" @click="applyPreset('coworking')" />
                </div>
            </div>

            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
                <div class="flex items-start justify-between gap-3">
                    <div class="min-w-0">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">Preset: Clínica com recepção</div>
                        <div class="mt-1 text-[1rem] text-[var(--text-color-secondary)]">Para secretária gerenciar agenda (pacientes opcional).</div>
                    </div>
                    <Button size="small" label="Aplicar" severity="secondary" outlined :loading="applyingPreset" :disabled="!isOwner || !tenantReady || loading || !!savingKey" @click="applyPreset('reception')" />
                </div>
            </div>

            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
                <div class="flex items-start justify-between gap-3">
                    <div class="min-w-0">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">Preset: Clínica completa</div>
                        <div class="mt-1 text-[1rem] text-[var(--text-color-secondary)]">Pacientes + recepção + salas (se quiser).</div>
                    </div>
                    <Button size="small" label="Aplicar" severity="secondary" outlined :loading="applyingPreset" :disabled="!isOwner || !tenantReady || loading || !!savingKey" @click="applyPreset('full')" />
                </div>
            </div>
        </div>

        <!-- Modules -->
        <div class="grid grid-cols-1 lg:grid-cols-2 gap-3">
            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
                <ModuleRow
                    title="Pacientes"
                    desc="Habilita gestão de pacientes por clínica. Todo paciente tem um responsável (therapist)."
                    icon="pi pi-users"
                    :enabled="isOn('patients')"
                    :loading="savingKey === 'patients'"
                    :disabled="isLocked('patients')"
                    @toggle="toggle('patients')"
                />
                <div v-if="planDenied.has('patients')" class="mt-3 text-[1rem] rounded-md border border-[var(--surface-border)] p-3 opacity-90">
                    <i class="pi pi-lock mr-2" />
                    Este módulo não está incluído no plano atual. Solicite ao suporte para liberar como exceção comercial.
                </div>
                <Divider class="my-4" />
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">
                    Quando desligado:
                    <ul class="mt-2 list-disc pl-5 space-y-1">
                        <li>Menu "Pacientes" some.</li>
                        <li>Rotas com <span class="font-mono">meta.tenantFeature = 'patients'</span> redirecionam pra cá.</li>
                        <li>RLS bloqueia acesso direto no banco.</li>
                    </ul>
                </div>
            </div>

            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
                <ModuleRow
                    title="Recepção / Secretária"
                    desc="Permite um papel de secretária gerenciar a agenda dos profissionais (sem precisar ver tudo do paciente)."
                    icon="pi pi-briefcase"
                    :enabled="isOn('shared_reception')"
                    :loading="savingKey === 'shared_reception'"
                    :disabled="isLocked('shared_reception')"
                    @toggle="toggle('shared_reception')"
                />
                <div v-if="planDenied.has('shared_reception')" class="mt-3 text-[1rem] rounded-md border border-[var(--surface-border)] p-3 opacity-90">
                    <i class="pi pi-lock mr-2" />
                    Este módulo não está incluído no plano atual. Solicite ao suporte para liberar como exceção comercial.
                </div>
                <Divider class="my-4" />
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">
                    Observação: este módulo é "produto" (UX + permissões). A base aqui é só o toggle. Depois a gente cria:
                    <ul class="mt-2 list-disc pl-5 space-y-1">
                        <li>role <span class="font-mono">secretary</span> em <span class="font-mono">tenant_members</span></li>
                        <li>policies e telas para a secretária</li>
                        <li>nível de visibilidade do paciente na agenda</li>
                    </ul>
                </div>
            </div>

            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
                <ModuleRow
                    title="Salas / Coworking"
                    desc="Habilita cadastro e reserva de salas/recursos no agendamento."
                    icon="pi pi-building"
                    :enabled="isOn('rooms')"
                    :loading="savingKey === 'rooms'"
                    :disabled="isLocked('rooms')"
                    @toggle="toggle('rooms')"
                />
                <div v-if="planDenied.has('rooms')" class="mt-3 text-[1rem] rounded-md border border-[var(--surface-border)] p-3 opacity-90">
                    <i class="pi pi-lock mr-2" />
                    Este módulo não está incluído no plano atual. Solicite ao suporte para liberar como exceção comercial.
                </div>
                <Divider class="my-4" />
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Isso prepara o terreno para a clínica operar como locação de sala, com agenda vinculando sala + profissional.</div>
            </div>

            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
                <ModuleRow
                    title="Link externo de cadastro"
                    desc="Libera fluxo público de intake/cadastro externo para a clínica."
                    icon="pi pi-link"
                    :enabled="isOn('intake_public')"
                    :loading="savingKey === 'intake_public'"
                    :disabled="isLocked('intake_public')"
                    @toggle="toggle('intake_public')"
                />
                <div v-if="planDenied.has('intake_public')" class="mt-3 text-[1rem] rounded-md border border-[var(--surface-border)] p-3 opacity-90">
                    <i class="pi pi-lock mr-2" />
                    Este módulo não está incluído no plano atual. Solicite ao suporte para liberar como exceção comercial.
                </div>
                <Divider class="my-4" />
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Você já tem páginas de link externo. Isso vira o controle fino: a clínica decide se usa ou não.</div>
            </div>
        </div>
    </div>
</template>

<style scoped></style>
