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

import InputNumber from 'primevue/inputnumber';
import { useToast } from 'primevue/usetoast';
import { useConfirm } from 'primevue/useconfirm';

const toast = useToast();
const confirm = useConfirm();

// ─── State ────────────────────────────────────────────────────────────────────
const loading = ref(false);
const saving = ref(false);

const plans = ref([]);
const features = ref([]);
const planFeatures = ref([]); // { plan_id, feature_id, enabled, limits }

const q = ref('');
const targetFilter = ref('all');
const targetOptions = [
    { label: 'Todos', value: 'all' },
    { label: 'Clínica', value: 'clinic' },
    { label: 'Terapeuta', value: 'therapist' }
];

// Dialog
const showDlg = ref(false);
const dlgPlan = ref(null); // plano selecionado
const dlgFeature = ref(null); // feature selecionada
const dlgPlanFeature = ref(null); // registro atual de plan_features

// Campos do form de limites (editável pelo admin)
// Cada "campo" é um par { key, label, type, value }
// O admin define quais keys existem em cada feature
const limitFields = ref([]);
const newLimitKey = ref('');
const newLimitValue = ref(null);
const newLimitType = ref('number'); // 'number' | 'boolean' | 'text'

const limitTypeOptions = [
    { label: 'Número', value: 'number' },
    { label: 'Texto', value: 'text' },
    { label: 'Booleano', value: 'boolean' }
];

// ─── Helpers ──────────────────────────────────────────────────────────────────
function targetLabel(t) {
    if (t === 'clinic') return 'Clínica';
    if (t === 'therapist') return 'Terapeuta';
    return '—';
}

function targetSeverity(t) {
    if (t === 'clinic') return 'info';
    if (t === 'therapist') return 'success';
    return 'secondary';
}

function featureDomain(key) {
    const k = String(key || '');
    if (k.includes('.')) return k.split('.')[0];
    if (k.includes('_')) return k.split('_')[0];
    return k;
}

function domainSeverity(domain) {
    const d = String(domain || '').toLowerCase();
    if (d.includes('agenda') || d.includes('scheduling')) return 'info';
    if (d.includes('billing') || d.includes('plano')) return 'success';
    if (d.includes('portal') || d.includes('patient')) return 'warn';
    return 'secondary';
}

function limitsDisplay(limits) {
    if (!limits || typeof limits !== 'object' || !Object.keys(limits).length) return '—';
    return Object.entries(limits)
        .map(([k, v]) => {
            if (v === -1 || v === null) return `${k}: ilimitado`;
            if (typeof v === 'boolean') return `${k}: ${v ? 'sim' : 'não'}`;
            return `${k}: ${v}`;
        })
        .join(' · ');
}

function limitValueDisplay(v) {
    if (v === null || v === undefined) return '—';
    if (v === -1) return 'Ilimitado';
    if (typeof v === 'boolean') return v ? 'Sim' : 'Não';
    return String(v);
}

// ─── Computeds ────────────────────────────────────────────────────────────────
const filteredPlans = computed(() => {
    let list = plans.value || [];
    if (targetFilter.value !== 'all') {
        list = list.filter((p) => p.target === targetFilter.value);
    }
    return list;
});

const filteredFeatures = computed(() => {
    const term = String(q.value || '')
        .trim()
        .toLowerCase();
    if (!term) return features.value;
    return (features.value || []).filter(
        (f) =>
            String(f.key || '')
                .toLowerCase()
                .includes(term) ||
            String(f.descricao || '')
                .toLowerCase()
                .includes(term)
    );
});

// Linha da tabela = 1 feature × N planos
const tableRows = computed(() => {
    return filteredFeatures.value.map((f) => {
        const planCols = {};
        for (const p of filteredPlans.value) {
            const pf = planFeatures.value.find((x) => x.plan_id === p.id && x.feature_id === f.id);
            planCols[p.id] = {
                enabled: pf?.enabled ?? false,
                limits: pf?.limits ?? null,
                hasRecord: !!pf
            };
        }
        return { feature: f, planCols };
    });
});

// ─── Fetch ────────────────────────────────────────────────────────────────────
async function fetchAll() {
    loading.value = true;
    try {
        const [{ data: p, error: ep }, { data: f, error: ef }, { data: pf, error: epf }] = await Promise.all([
            supabase.from('plans').select('id,key,name,target,is_active').order('key'),
            supabase.from('features').select('id,key,name,descricao').order('key'),
            supabase.from('plan_features').select('plan_id,feature_id,enabled,limits')
        ]);

        if (ep) throw ep;
        if (ef) throw ef;
        if (epf) throw epf;

        plans.value = p || [];
        features.value = f || [];
        planFeatures.value = pf || [];
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 4500 });
    } finally {
        loading.value = false;
    }
}

// ─── Dialog: abrir ────────────────────────────────────────────────────────────
function openLimits(plan, feature) {
    if (saving.value) return;

    dlgPlan.value = plan;
    dlgFeature.value = feature;

    const pf = planFeatures.value.find((x) => x.plan_id === plan.id && x.feature_id === feature.id);
    dlgPlanFeature.value = pf || null;

    // Monta campos a partir dos limits existentes
    const existingLimits = pf?.limits && typeof pf.limits === 'object' ? pf.limits : {};
    limitFields.value = Object.entries(existingLimits).map(([key, value]) => ({
        key,
        value,
        type: typeof value === 'boolean' ? 'boolean' : typeof value === 'number' ? 'number' : 'text'
    }));

    newLimitKey.value = '';
    newLimitValue.value = null;
    newLimitType.value = 'number';

    showDlg.value = true;
}

// ─── Dialog: add campo ────────────────────────────────────────────────────────
function addLimitField() {
    const k = String(newLimitKey.value || '')
        .trim()
        .toLowerCase()
        .replace(/\s+/g, '_')
        .replace(/[^a-z0-9_]/g, '');

    if (!k) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: 'Informe o nome do limite (ex: max_patients).', life: 3000 });
        return;
    }

    if (limitFields.value.some((f) => f.key === k)) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: 'Já existe um campo com esse nome.', life: 3000 });
        return;
    }

    let v = newLimitValue.value;
    if (newLimitType.value === 'boolean') v = !!v;
    else if (newLimitType.value === 'number') v = v ?? 0;
    else v = String(v ?? '');

    limitFields.value.push({ key: k, value: v, type: newLimitType.value });
    newLimitKey.value = '';
    newLimitValue.value = null;
}

function removeLimitField(index) {
    limitFields.value.splice(index, 1);
}

function setUnlimited(index) {
    limitFields.value[index].value = -1;
    limitFields.value[index].type = 'number';
}

// ─── Dialog: salvar ───────────────────────────────────────────────────────────
async function saveLimits() {
    if (!dlgPlan.value || !dlgFeature.value) return;
    if (saving.value) return;

    saving.value = true;
    try {
        // Monta o objeto limits a partir dos campos
        const limits = {};
        for (const field of limitFields.value) {
            let v = field.value;
            if (field.type === 'boolean') v = !!v;
            else if (field.type === 'number') v = v === null ? 0 : Number(v);
            else v = String(v ?? '');
            limits[field.key] = v;
        }

        const payload = {
            plan_id: dlgPlan.value.id,
            feature_id: dlgFeature.value.id,
            enabled: dlgPlanFeature.value?.enabled ?? true,
            limits: Object.keys(limits).length ? limits : null
        };

        const { error } = await supabase.from('plan_features').upsert(payload, { onConflict: 'plan_id,feature_id' });

        if (error) throw error;

        toast.add({ severity: 'success', summary: 'Ok', detail: 'Limites salvos.', life: 2500 });
        showDlg.value = false;
        await fetchAll();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 4500 });
    } finally {
        saving.value = false;
    }
}

// ─── Limpar limites ───────────────────────────────────────────────────────────
function askClearLimits(plan, feature) {
    const pf = planFeatures.value.find((x) => x.plan_id === plan.id && x.feature_id === feature.id);
    if (!pf || !pf.limits) {
        toast.add({ severity: 'info', summary: 'Nada a limpar', detail: 'Este plano/feature não tem limites definidos.', life: 2500 });
        return;
    }

    confirm.require({
        message: `Remover todos os limites de "${feature.key}" no plano "${plan.key}"?\n\nO acesso continuará habilitado, mas sem restrições de quantidade.`,
        header: 'Confirmar remoção de limites',
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-danger',
        accept: () => doClearLimits(plan, feature)
    });
}

async function doClearLimits(plan, feature) {
    try {
        const { error } = await supabase.from('plan_features').update({ limits: null }).eq('plan_id', plan.id).eq('feature_id', feature.id);

        if (error) throw error;

        toast.add({ severity: 'success', summary: 'Ok', detail: 'Limites removidos.', life: 2500 });
        await fetchAll();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 4500 });
    }
}

// ── Hero sticky ───────────────────────────────────────────
const heroEl = ref(null);
const heroSentinelRef = ref(null);
const heroMenuRef = ref(null);
const heroStuck = ref(false);
let disconnectStickyObserver = null;

const heroMenuItems = computed(() => [
    { label: 'Recarregar', icon: 'pi pi-refresh', command: fetchAll, disabled: loading.value || saving.value },
    { separator: true },
    {
        label: 'Filtrar por público',
        items: targetOptions.map((o) => ({
            label: o.label,
            command: () => {
                targetFilter.value = o.value;
            }
        }))
    }
]);

onMounted(async () => {
    await fetchAll();

    const sentinel = heroSentinelRef.value;
    if (sentinel) {
        const io = new IntersectionObserver(
            ([entry]) => {
                heroStuck.value = !entry.isIntersecting;
            },
            { rootMargin: `${document.querySelector('.l2-main') ? '0px' : '-56px'} 0px 0px 0px` }
        );
        io.observe(sentinel);
        disconnectStickyObserver = () => io.disconnect();
    }
});

onBeforeUnmount(() => {
    try {
        disconnectStickyObserver?.();
    } catch {}
});
</script>

<template>
    <ConfirmDialog />

    <div class="flex flex-col gap-4 p-4">
        <!-- Header -->
        <div class="cfg-subheader">
            <div class="cfg-subheader__icon"><i class="pi pi-sliders-h" /></div>
            <div class="min-w-0 flex-1">
                <div class="cfg-subheader__title">Limites por Plano</div>
                <div class="cfg-subheader__sub">Configure os limites reais de cada feature por plano.</div>
            </div>
            <div class="hidden xl:flex items-center gap-2 shrink-0">
                <SelectButton v-model="targetFilter" :options="targetOptions" optionLabel="label" optionValue="value" size="small" :disabled="loading || saving" />
                <Button label="Recarregar" icon="pi pi-refresh" severity="secondary" outlined size="small" :loading="loading" :disabled="saving" @click="fetchAll" />
            </div>
            <div class="flex xl:hidden shrink-0">
                <Button label="Ações" icon="pi pi-ellipsis-v" severity="warn" size="small" aria-haspopup="true" aria-controls="limits_hero_menu" @click="(e) => heroMenuRef.toggle(e)" />
                <Menu ref="heroMenuRef" id="limits_hero_menu" :model="heroMenuItems" :popup="true" />
            </div>
        </div>
        <!-- Search -->
        <div>
            <FloatLabel variant="on" class="w-full md:w-80">
                <IconField class="w-full">
                    <InputIcon class="pi pi-search" />
                    <InputText v-model="q" id="limits_search" class="w-full pr-10" variant="filled" :disabled="loading || saving" autocomplete="off" />
                </IconField>
                <label for="limits_search">Filtrar features (key ou descrição)</label>
            </FloatLabel>
        </div>

        <!-- Legenda rápida -->
        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3">
            <div class="flex flex-wrap gap-4 items-center">
                <div class="flex items-center gap-2 text-[1rem] text-[var(--text-color-secondary)]">
                    <i class="pi pi-info-circle text-blue-400" />
                    <span><strong>Sem limites</strong> = acesso habilitado sem restrição de quantidade</span>
                </div>
                <div class="flex items-center gap-2 text-[1rem] text-[var(--text-color-secondary)]">
                    <i class="pi pi-info-circle text-orange-400" />
                    <span><strong>-1</strong> = ilimitado (explícito no JSON, útil para planos PRO)</span>
                </div>
                <div class="flex items-center gap-2 text-[1rem] text-[var(--text-color-secondary)]">
                    <i class="pi pi-info-circle text-red-400" />
                    <span><strong>0 ou N</strong> = limite máximo que o sistema vai verificar</span>
                </div>
                <div class="flex items-center gap-2 ml-auto">
                    <Tag :value="`${filteredPlans.length} plano(s)`" severity="info" icon="pi pi-star" rounded />
                    <Tag :value="`${filteredFeatures.length} feature(s)`" severity="success" icon="pi pi-bolt" rounded />
                </div>
            </div>
        </div>

        <!-- Tabela: feature × planos -->
        <DataTable :value="tableRows" dataKey="feature.id" :loading="loading" stripedRows responsiveLayout="scroll" :scrollable="true" scrollHeight="65vh">
            <!-- Coluna fixa: Feature -->
            <Column header="Feature" frozen style="min-width: 26rem">
                <template #body="{ data }">
                    <div class="flex flex-col">
                        <div class="flex items-center gap-2">
                            <Tag :value="featureDomain(data.feature.key)" :severity="domainSeverity(featureDomain(data.feature.key))" rounded />
                            <span class="font-medium font-mono text-[1rem]">{{ data.feature.key }}</span>
                        </div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1 leading-snug">
                            {{ data.feature.descricao || '—' }}
                        </div>
                    </div>
                </template>
            </Column>

            <!-- Coluna dinâmica: 1 por plano filtrado -->
            <Column v-for="plan in filteredPlans" :key="plan.id" :style="{ minWidth: '20rem' }">
                <template #header>
                    <div class="flex flex-col gap-1 w-full">
                        <div class="flex items-center justify-between gap-2">
                            <span class="font-semibold truncate" :title="plan.name">{{ plan.name || plan.key }}</span>
                            <Tag :value="targetLabel(plan.target)" :severity="targetSeverity(plan.target)" rounded />
                        </div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)] font-mono">{{ plan.key }}</div>
                    </div>
                </template>

                <template #body="{ data }">
                    <div class="flex flex-col gap-2">
                        <!-- Status: habilitado ou não -->
                        <div class="flex items-center gap-2">
                            <Tag v-if="data.planCols[plan.id].hasRecord" :value="data.planCols[plan.id].enabled ? 'Habilitado' : 'Desabilitado'" :severity="data.planCols[plan.id].enabled ? 'success' : 'secondary'" rounded />
                            <Tag v-else value="Sem vínculo" severity="secondary" rounded />
                        </div>

                        <!-- Limites atuais -->
                        <div v-if="data.planCols[plan.id].limits" class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-2">
                            <div v-for="(val, key) in data.planCols[plan.id].limits" :key="key" class="flex items-center gap-1">
                                <span class="font-mono font-medium">{{ key }}:</span>
                                <span>{{ limitValueDisplay(val) }}</span>
                            </div>
                        </div>
                        <div v-else-if="data.planCols[plan.id].hasRecord" class="text-[1rem] text-[var(--text-color-secondary)]">Sem limites definidos</div>

                        <!-- Ações -->
                        <div v-if="data.planCols[plan.id].hasRecord" class="flex gap-2 flex-wrap">
                            <Button icon="pi pi-pencil" size="small" severity="secondary" outlined v-tooltip.top="'Editar limites'" :disabled="loading || saving" @click="openLimits(plan, data.feature)" />
                            <Button icon="pi pi-times" size="small" severity="danger" outlined v-tooltip.top="'Limpar limites'" :disabled="loading || saving || !data.planCols[plan.id].limits" @click="askClearLimits(plan, data.feature)" />
                        </div>
                        <div v-else class="text-[1rem] text-[var(--text-color-secondary)] italic">
                            Feature não vinculada a este plano.<br />
                            Configure em <strong>Recursos por Plano</strong>.
                        </div>
                    </div>
                </template>
            </Column>
        </DataTable>
    </div>

    <!-- Dialog: editar limites de plan_features -->
    <Dialog v-model:visible="showDlg" modal :draggable="false" :closable="!saving" :dismissableMask="!saving" :style="{ width: '680px' }">
        <template #header>
            <div class="flex flex-col gap-1">
                <div class="text-[1rem] font-semibold">Limites — {{ dlgFeature?.key }}</div>
                <div class="flex items-center gap-2 flex-wrap">
                    <Tag :value="dlgPlan?.name || dlgPlan?.key" severity="secondary" />
                    <Tag :value="targetLabel(dlgPlan?.target)" :severity="targetSeverity(dlgPlan?.target)" rounded />
                </div>
            </div>
        </template>

        <div class="flex flex-col gap-4">
            <!-- Campos existentes -->
            <div v-if="limitFields.length">
                <div class="font-semibold mb-2">Limites configurados</div>
                <div class="flex flex-col gap-2">
                    <div v-for="(field, idx) in limitFields" :key="idx" class="flex items-center gap-3 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3">
                        <!-- Key (não editável) -->
                        <div class="flex-1 min-w-0">
                            <div class="font-mono font-medium text-[1rem]">{{ field.key }}</div>
                            <div class="text-[1rem] text-[var(--text-color-secondary)]">{{ field.type }}</div>
                        </div>

                        <!-- Valor -->
                        <div class="w-40 shrink-0">
                            <template v-if="field.type === 'number'">
                                <InputNumber v-model="field.value" class="w-full" inputClass="w-full" :disabled="saving" :min="-1" placeholder="-1 = ilimitado" />
                            </template>
                            <template v-else-if="field.type === 'boolean'">
                                <SelectButton
                                    v-model="field.value"
                                    :options="[
                                        { label: 'Sim', value: true },
                                        { label: 'Não', value: false }
                                    ]"
                                    optionLabel="label"
                                    optionValue="value"
                                    :disabled="saving"
                                />
                            </template>
                            <template v-else>
                                <InputText v-model="field.value" class="w-full" :disabled="saving" />
                            </template>
                        </div>

                        <!-- Ações rápidas -->
                        <div class="flex gap-1 shrink-0">
                            <Button icon="pi pi-infinity" size="small" severity="secondary" outlined v-tooltip.top="'Definir como ilimitado (-1)'" :disabled="saving || field.type !== 'number'" @click="setUnlimited(idx)" />
                            <Button icon="pi pi-trash" size="small" severity="danger" outlined v-tooltip.top="'Remover este campo'" :disabled="saving" @click="removeLimitField(idx)" />
                        </div>
                    </div>
                </div>
            </div>

            <div v-else class="text-[1rem] text-[var(--text-color-secondary)] rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 text-center">Nenhum limite configurado. Adicione abaixo.</div>

            <Divider />

            <!-- Adicionar novo campo -->
            <div>
                <div class="font-semibold mb-3">Adicionar campo de limite</div>

                <div class="flex flex-col gap-3">
                    <!-- Nome -->
                    <div>
                        <label class="text-[1rem] font-semibold text-[var(--text-color-secondary)] uppercase tracking-wide block mb-1"> Nome do campo * </label>
                        <InputText id="new-limit-key" v-model="newLimitKey" class="w-full" variant="filled" :disabled="saving" autocomplete="off" placeholder="ex: max_patients" @keydown.enter.prevent="addLimitField" />
                        <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1">Ex: <span class="font-mono">max_patients</span>, <span class="font-mono">max_sessions_per_month</span></div>
                    </div>

                    <!-- Tipo + Valor + Botão -->
                    <div class="flex items-end gap-2 flex-wrap">
                        <div>
                            <label class="text-[1rem] font-semibold text-[var(--text-color-secondary)] uppercase tracking-wide block mb-1">Tipo</label>
                            <SelectButton v-model="newLimitType" :options="limitTypeOptions" optionLabel="label" optionValue="value" :disabled="saving" />
                        </div>

                        <div class="flex-1" style="min-width: 8rem">
                            <label class="text-[1rem] font-semibold text-[var(--text-color-secondary)] uppercase tracking-wide block mb-1">Valor inicial</label>
                            <InputNumber v-if="newLimitType === 'number'" v-model="newLimitValue" class="w-full" inputClass="w-full" variant="filled" :disabled="saving" :min="-1" placeholder="-1 = ilimitado" />
                            <SelectButton
                                v-else-if="newLimitType === 'boolean'"
                                v-model="newLimitValue"
                                :options="[
                                    { label: 'Sim', value: true },
                                    { label: 'Não', value: false }
                                ]"
                                optionLabel="label"
                                optionValue="value"
                                :disabled="saving"
                            />
                            <InputText v-else v-model="newLimitValue" class="w-full" variant="filled" :disabled="saving" />
                        </div>

                        <Button icon="pi pi-plus" label="Adicionar" :disabled="saving || !newLimitKey?.trim()" @click="addLimitField" />
                    </div>
                </div>
            </div>

            <!-- Dica de boas práticas -->
            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">
                <div class="font-semibold mb-1">Convenções recomendadas</div>
                <div class="grid grid-cols-2 gap-x-4 gap-y-1">
                    <div><span class="font-mono">max_patients</span> — número máximo de pacientes</div>
                    <div><span class="font-mono">max_sessions_per_month</span> — sessões/mês</div>
                    <div><span class="font-mono">max_members</span> — membros da clínica</div>
                    <div><span class="font-mono">max_therapists</span> — terapeutas vinculados</div>
                    <div><span class="font-mono">-1</span> — sem limite (planos PRO)</div>
                    <div><span class="font-mono">0</span> — bloqueado completamente</div>
                </div>
            </div>
        </div>

        <template #footer>
            <Button label="Cancelar" severity="secondary" outlined :disabled="saving" @click="showDlg = false" />
            <Button label="Salvar limites" icon="pi pi-check" :loading="saving" @click="saveLimits" />
        </template>
    </Dialog>
</template>