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

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

// ── Constantes ──────────────────────────────────────────────────
const CHANNELS = [
    { label: 'WhatsApp', value: 'whatsapp', icon: 'pi pi-whatsapp' },
    { label: 'SMS', value: 'sms', icon: 'pi pi-mobile' }
];

const DOMAIN_OPTIONS = [
    { label: 'Sessão', value: 'session' },
    { label: 'Triagem', value: 'intake' },
    { label: 'Financeiro', value: 'billing' },
    { label: 'Sistema', value: 'system' }
];

const EVENT_TYPE_OPTIONS = [
    { label: 'Lembrete de sessão', value: 'lembrete_sessao' },
    { label: 'Confirmação de sessão', value: 'confirmacao_sessao' },
    { label: 'Cancelamento de sessão', value: 'cancelamento_sessao' },
    { label: 'Reagendamento', value: 'reagendamento' },
    { label: 'Cobrança pendente', value: 'cobranca_pendente' },
    { label: 'Boas-vindas paciente', value: 'boas_vindas_paciente' },
    { label: 'Intake recebido', value: 'intake_recebido' },
    { label: 'Intake aprovado', value: 'intake_aprovado' },
    { label: 'Intake rejeitado', value: 'intake_rejeitado' }
];

const EVENT_TYPE_LABELS = Object.fromEntries(EVENT_TYPE_OPTIONS.map((e) => [e.value, e.label]));
const DOMAIN_LABELS = { session: 'Sessão', intake: 'Triagem', billing: 'Financeiro', system: 'Sistema' };
const DOMAIN_SEVERITY = { session: 'info', intake: 'warning', billing: 'success', system: 'secondary' };

const VARS_BY_EVENT = {
    lembrete_sessao: ['patient_name', 'session_date', 'session_time', 'therapist_name', 'session_modality', 'session_link'],
    confirmacao_sessao: ['patient_name', 'session_date', 'session_time', 'therapist_name', 'session_modality'],
    cancelamento_sessao: ['patient_name', 'session_date', 'session_time', 'therapist_name', 'cancellation_reason'],
    reagendamento: ['patient_name', 'session_date', 'session_time', 'therapist_name', 'session_modality'],
    cobranca_pendente: ['patient_name', 'therapist_name', 'valor', 'vencimento'],
    boas_vindas_paciente: ['patient_name', 'clinic_name', 'therapist_name', 'portal_link'],
    intake_recebido: ['patient_name', 'clinic_name', 'therapist_name'],
    intake_aprovado: ['patient_name', 'therapist_name', 'session_date', 'session_time'],
    intake_rejeitado: ['patient_name', 'therapist_name', 'rejection_reason']
};

// ── Estado ──────────────────────────────────────────────────────
const activeChannel = ref('whatsapp');
const templates = ref([]);
const loading = ref(false);

// ── Load ────────────────────────────────────────────────────────
async function load() {
    loading.value = true;
    try {
        const { data, error } = await supabase.rpc('saas_list_default_notif_templates');
        if (error) throw error;
        // RPC retorna array direto com as linhas completas dos templates default
        templates.value = (data || []).slice().sort((a, b) => (a.domain || '').localeCompare(b.domain || '') || (a.event_type || '').localeCompare(b.event_type || ''));
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao carregar', detail: e.message, life: 4000 });
    } finally {
        loading.value = false;
    }
}

const filtered = computed(() => templates.value.filter((t) => t.channel === activeChannel.value));

// ── Dialog ──────────────────────────────────────────────────────
const dlg = ref({ open: false, saving: false, id: null, isNew: false });
const form = ref({});
const bodyTextareaRef = ref(null);

function _emptyForm() {
    return {
        key: '',
        domain: 'session',
        channel: activeChannel.value,
        event_type: 'lembrete_sessao',
        body_text: '',
        is_active: true
    };
}

function openNew() {
    form.value = _emptyForm();
    dlg.value = { open: true, saving: false, id: null, isNew: true };
}

function openEdit(t) {
    form.value = {
        key: t.key,
        domain: t.domain,
        channel: t.channel,
        event_type: t.event_type,
        body_text: t.body_text,
        is_active: t.is_active
    };
    dlg.value = { open: true, saving: false, id: t.id, isNew: false };
}

function closeDlg() {
    dlg.value.open = false;
}

// Variáveis disponíveis para o event_type selecionado
const availableVars = computed(() => VARS_BY_EVENT[form.value.event_type] || []);

// Variáveis detectadas no body_text
const detectedVars = computed(() => {
    const matches = (form.value.body_text || '').matchAll(/\{\{(\w+)\}\}/g);
    return [...new Set([...matches].map((m) => m[1]))];
});

// Insere variável no cursor do textarea
function insertVar(varName) {
    const snippet = `{{${varName}}}`;
    const ta = bodyTextareaRef.value?.$el?.querySelector('textarea');
    if (!ta) {
        form.value.body_text = (form.value.body_text || '') + snippet;
        return;
    }
    const start = ta.selectionStart ?? ta.value.length;
    const end = ta.selectionEnd ?? start;
    const val = form.value.body_text || '';
    form.value.body_text = val.slice(0, start) + snippet + val.slice(end);
    nextTick(() => {
        const pos = start + snippet.length;
        ta.focus();
        ta.setSelectionRange(pos, pos);
    });
}

// ── Save ────────────────────────────────────────────────────────
async function save() {
    if (!form.value.body_text?.trim()) {
        toast.add({ severity: 'warn', summary: 'Mensagem é obrigatória', life: 3000 });
        return;
    }
    if (dlg.value.isNew && !form.value.key?.trim()) {
        toast.add({ severity: 'warn', summary: 'Key é obrigatória', life: 3000 });
        return;
    }

    dlg.value.saving = true;
    try {
        // Detecta variáveis usadas
        const vars = [...(form.value.body_text || '').matchAll(/\{\{(\w+)\}\}/g)].map((m) => m[1]);

        // Upsert por key (cria se nova, atualiza se já existe; propaga ao _tenant_template + schemas)
        const payload = {
            key: form.value.key,
            domain: form.value.domain,
            channel: form.value.channel,
            event_type: form.value.event_type,
            body_text: form.value.body_text,
            variables: vars,
            is_active: form.value.is_active
        };
        const { error } = await supabase.rpc('saas_upsert_default_notif_template', { p_payload: payload });
        if (error) throw error;

        toast.add({ severity: 'success', summary: dlg.value.isNew ? 'Template criado' : 'Template atualizado', life: 3000 });
        closeDlg();
        await load();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao salvar', detail: e.message, life: 5000 });
    } finally {
        dlg.value.saving = false;
    }
}

// ── Toggle ativo ────────────────────────────────────────────────
const togglingId = ref(null);

async function countAffectedTenants(t) {
    // TODO(schema-per-tenant): a RPC retorna o nº de tenants COM override ativo desta key.
    // A métrica antiga contava tenants agendando SEM override (impacto de desativar o default).
    // Semântica mudou; o número exibido na confirmação agora reflete overrides, não impacto direto.
    const { data, error } = await supabase.rpc('saas_count_notif_template_overrides', { p_key: t.key });
    if (error) throw error;
    return data || 0;
}

async function doToggleActive(t) {
    togglingId.value = t.id;
    try {
        const next = !t.is_active;
        const { error } = await supabase.rpc('saas_set_default_notif_template_active', { p_key: t.key, p_active: next });
        if (error) throw error;
        t.is_active = next;
        toast.add({
            severity: next ? 'success' : 'warn',
            summary: next ? 'Template reativado' : 'Template desativado',
            detail: next ? 'Tenants voltam a usar este template padrão.' : 'Tenants sem personalização ficarão sem este template.',
            life: 3500
        });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e.message, life: 4000 });
    } finally {
        togglingId.value = null;
    }
}

async function requestToggleActive(t) {
    if (togglingId.value) return;

    if (!t.is_active) {
        await doToggleActive(t);
        return;
    }

    togglingId.value = t.id;
    let affectedCount = 0;
    try {
        affectedCount = await countAffectedTenants(t);
    } catch {
        // silenciosamente ignora — mostramos aviso genérico
    } finally {
        togglingId.value = null;
    }

    const channelLabel = t.channel === 'whatsapp' ? 'WhatsApp' : 'SMS';
    const eventLabel = EVENT_TYPE_LABELS[t.event_type] || t.event_type;

    const impactLine =
        affectedCount > 0
            ? `<strong>${affectedCount} ${affectedCount === 1 ? 'tenant está' : 'tenants estão'}</strong> agendando este evento sem template personalizado — ${affectedCount === 1 ? 'ficará' : 'ficarão'} sem mensagem.`
            : 'Atualmente nenhum tenant depende deste template, mas futuros eventos não terão mensagem padrão.';

    const msg = [
        `Você vai desativar o template padrão de <strong>${channelLabel}</strong> para o evento "<strong>${eventLabel}</strong>".`,
        impactLine,
        'Tenants com template personalizado <strong>NÃO</strong> são afetados.'
    ].join('<br><br>');

    confirm.require({
        group: 'headless',
        header: `Desativar "${eventLabel}"?`,
        message: msg,
        icon: 'pi-exclamation-triangle',
        color: '#f59e0b',
        accept: () => doToggleActive(t)
    });
}

// ── Soft delete ─────────────────────────────────────────────────
function deleteTemplate(t) {
    confirm.require({
        group: 'headless',
        message: `Excluir o template "${t.key}"?`,
        header: 'Confirmar exclusão',
        icon: 'pi-trash',
        color: '#ef4444',
        accept: async () => {
            try {
                const { error } = await supabase.rpc('saas_delete_default_notif_template', { p_key: t.key });
                if (error) throw error;
                toast.add({ severity: 'success', summary: 'Template excluído', life: 3000 });
                await load();
            } catch (e) {
                toast.add({ severity: 'error', summary: 'Erro', detail: e.message, life: 4000 });
            }
        }
    });
}

// ── Truncate ────────────────────────────────────────────────────
function truncate(str, len = 80) {
    if (!str) return '';
    return str.length > len ? str.slice(0, len) + '…' : str;
}

onMounted(load);
</script>

<template>
    <ConfirmDialog group="headless">
        <template #container="{ message, acceptCallback, rejectCallback }">
            <div class="flex flex-col items-center p-8 bg-surface-0 dark:bg-surface-900 rounded-xl shadow-xl">
                <div class="rounded-full inline-flex justify-center items-center h-24 w-24 -mt-20" :style="{ background: message.color || 'var(--p-primary-color)', color: '#fff' }">
                    <i :class="`pi ${message.icon || 'pi-question'} !text-4xl`"></i>
                </div>
                <span class="font-bold text-2xl block mb-2 mt-6">{{ message.header }}</span>
                <p class="mb-0 text-center text-[var(--text-color-secondary)]" v-html="message.message"></p>
                <div class="flex items-center gap-2 mt-6">
                    <Button label="Confirmar" class="rounded-full" :style="{ background: message.color || 'var(--p-primary-color)', borderColor: message.color || 'var(--p-primary-color)' }" @click="acceptCallback" />
                    <Button label="Cancelar" variant="outlined" class="rounded-full" @click="rejectCallback" />
                </div>
            </div>
        </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-comment" /></div>
            <div class="min-w-0 flex-1">
                <div class="cfg-subheader__title">Templates de Notificação</div>
                <div class="cfg-subheader__sub">Templates globais de WhatsApp e SMS. Tenants herdam automaticamente.</div>
            </div>
            <div class="flex gap-2 shrink-0">
                <Button label="Novo template" icon="pi pi-plus" size="small" @click="openNew" />
                <Button icon="pi pi-refresh" severity="secondary" text :loading="loading" v-tooltip.bottom="'Recarregar'" @click="load" />
            </div>
        </div>

        <!-- Tabs canal -->
        <div class="flex gap-2 flex-wrap">
            <Button v-for="ch in CHANNELS" :key="ch.value" :label="ch.label" :icon="ch.icon" size="small" :severity="activeChannel === ch.value ? 'primary' : 'secondary'" :outlined="activeChannel !== ch.value" @click="activeChannel = ch.value" />
        </div>

        <!-- Loading -->
        <div v-if="loading" class="flex justify-center py-12">
            <ProgressSpinner />
        </div>

        <!-- DataTable encapsulada em card -->
        <div v-else class="rounded-[6px] border border-[var(--surface-border)] bg-[var(--surface-card)] overflow-hidden">
        <DataTable :value="filtered" stripedRows size="small" class="text-sm" :rowClass="(data) => (!data.is_active ? 'opacity-50' : '')">
            <Column field="key" header="Key" sortable style="min-width: 200px">
                <template #body="{ data }">
                    <code class="font-mono text-xs">{{ data.key }}</code>
                </template>
            </Column>

            <Column field="domain" header="Domínio" sortable style="width: 110px">
                <template #body="{ data }">
                    <Tag :value="DOMAIN_LABELS[data.domain] ?? data.domain" :severity="DOMAIN_SEVERITY[data.domain] ?? 'secondary'" class="text-[0.65rem]" />
                </template>
            </Column>

            <Column field="event_type" header="Evento" sortable style="min-width: 160px">
                <template #body="{ data }">
                    <span class="text-xs">{{ EVENT_TYPE_LABELS[data.event_type] ?? data.event_type }}</span>
                </template>
            </Column>

            <Column field="body_text" header="Mensagem" style="min-width: 200px">
                <template #body="{ data }">
                    <span class="text-xs text-[var(--text-color-secondary)]">{{ truncate(data.body_text) }}</span>
                </template>
            </Column>

            <Column field="version" header="v" sortable style="width: 50px" class="text-center">
                <template #body="{ data }">
                    <span class="text-xs text-[var(--text-color-secondary)]">{{ data.version }}</span>
                </template>
            </Column>

            <Column header="Ativo" style="width: 70px" class="text-center">
                <template #body="{ data }">
                    <ToggleSwitch :modelValue="data.is_active" :disabled="togglingId === data.id" @update:modelValue="() => requestToggleActive(data)" />
                </template>
            </Column>

            <Column header="" style="width: 90px">
                <template #body="{ data }">
                    <div class="flex gap-1">
                        <Button icon="pi pi-pencil" text rounded size="small" @click="openEdit(data)" />
                        <Button icon="pi pi-trash" text rounded size="small" severity="danger" @click="deleteTemplate(data)" />
                    </div>
                </template>
            </Column>

            <template #empty>
                <div class="text-center py-8 text-[var(--text-color-secondary)]">
                    <i class="pi pi-comment text-3xl opacity-30 block mb-2" />
                    Nenhum template {{ activeChannel === 'sms' ? 'SMS' : 'WhatsApp' }} cadastrado.
                </div>
            </template>
        </DataTable>
        </div>

        <!-- ── Dialog Cadastro / Edição ──────────────────────────────── -->
        <Dialog
            v-model:visible="dlg.open"
            modal
            :draggable="false"
            :closable="!dlg.saving"
            :dismissableMask="!dlg.saving"
            maximizable
            class="dc-dialog w-[50rem]"
            :breakpoints="{ '1199px': '90vw', '768px': '94vw' }"
            :pt="{
                header: { class: '!p-3 !rounded-t-[12px] border-b border-[var(--surface-border)] bg-[var(--surface-ground)]' },
                content: { class: '!p-3' },
                footer: { class: '!p-0 !rounded-b-[12px] border-t border-[var(--surface-border)] bg-[var(--surface-ground)]' },
                pcCloseButton: { root: { class: '!rounded-md hover:!text-red-500' } },
                pcMaximizeButton: { root: { class: '!rounded-md hover:!text-primary' } }
            }"
            pt:mask:class="backdrop-blur-xs"
        >
            <template #header>
                <div class="flex w-full items-center justify-between gap-3 px-1">
                    <div class="flex items-center gap-3 min-w-0">
                        <div class="min-w-0">
                            <div class="text-base font-semibold truncate">{{ dlg.isNew ? 'Novo Template' : 'Editar Template' }}</div>
                            <div class="text-xs opacity-50">{{ dlg.isNew ? 'Cadastrar novo template de notificação' : form.key }}</div>
                        </div>
                    </div>
                </div>
            </template>
            <div class="flex flex-col gap-4 py-2">
                <!-- Key + Channel (somente no cadastro) -->
                <div v-if="dlg.isNew" class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div class="flex flex-col gap-1.5">
                        <label class="text-xs font-semibold">Key *</label>
                        <InputText v-model="form.key" class="w-full font-mono text-sm" placeholder="ex: session.reminder.sms" />
                    </div>
                    <div class="flex flex-col gap-1.5">
                        <label class="text-xs font-semibold">Canal</label>
                        <Select v-model="form.channel" :options="CHANNELS" option-label="label" option-value="value" class="w-full" />
                    </div>
                </div>

                <div v-else class="flex flex-col gap-1.5">
                    <label class="text-xs font-semibold">Key</label>
                    <InputText :model-value="form.key" class="w-full font-mono text-sm" disabled />
                </div>

                <!-- Domain + Event Type -->
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div class="flex flex-col gap-1.5">
                        <label class="text-xs font-semibold">Domínio</label>
                        <Select v-model="form.domain" :options="DOMAIN_OPTIONS" option-label="label" option-value="value" class="w-full" />
                    </div>
                    <div class="flex flex-col gap-1.5">
                        <label class="text-xs font-semibold">Tipo de evento</label>
                        <Select v-model="form.event_type" :options="EVENT_TYPE_OPTIONS" option-label="label" option-value="value" class="w-full" />
                    </div>
                </div>

                <!-- Body text -->
                <div class="flex flex-col gap-2">
                    <label class="text-xs font-semibold">Mensagem *</label>
                    <Textarea ref="bodyTextareaRef" v-model="form.body_text" rows="6" auto-resize class="w-full text-sm" />

                    <!-- Chips de variáveis -->
                    <div v-if="availableVars.length" class="flex flex-col gap-1.5">
                        <span class="text-xs text-[var(--text-color-secondary)]">Inserir variável no cursor:</span>
                        <div class="flex flex-wrap gap-1.5">
                            <Button v-for="v in availableVars" :key="v" :label="`{{${v}}}`" size="small" severity="secondary" outlined class="font-mono !text-[0.68rem] !py-1 !px-2" @click="insertVar(v)" />
                        </div>
                    </div>

                    <!-- Variáveis detectadas -->
                    <div v-if="detectedVars.length" class="flex items-center gap-1.5 flex-wrap">
                        <span class="text-xs text-[var(--text-color-secondary)]">Variáveis usadas:</span>
                        <Tag v-for="v in detectedVars" :key="v" :value="v" severity="info" class="!text-[0.6rem] font-mono" />
                    </div>
                </div>

                <!-- Ativo -->
                <div class="flex items-center gap-2 pt-1">
                    <ToggleSwitch v-model="form.is_active" inputId="sw-active-tpl" />
                    <label for="sw-active-tpl" class="text-sm cursor-pointer select-none">Ativo</label>
                </div>
            </div>

            <template #footer>
                <div class="flex items-center justify-end gap-2 px-3 py-3">
                    <Button label="Cancelar" severity="secondary" text class="rounded-full hover:!text-red-500" :disabled="dlg.saving" @click="closeDlg" />
                    <Button :label="dlg.isNew ? 'Criar template' : 'Salvar'" icon="pi pi-check" class="rounded-full" :loading="dlg.saving" @click="save" />
                </div>
            </template>
        </Dialog>
    </div>
</template>