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

import TabView from 'primevue/tabview';
import TabPanel from 'primevue/tabpanel';

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

import { supabase } from '@/lib/supabase/client';
import { useTenantStore } from '@/stores/tenantStore';

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

const debug = false;
const router = useRouter();

function openInvitePrefill(email, type = 'therapist') {
    invite.value.open = true;
    invite.value.type = type;
    invite.value.email = normalizeEmail(email);
    invite.value.loading = false;
    invite.value.error = '';
}

// --------------------
// Equipe (tenant_members)
// --------------------
const loading = ref(false);
const loadError = ref('');
const search = ref('');
const members = ref([]);

// --------------------
// Convites pendentes (tenant_invites)
// --------------------
const invites = ref([]);
const loadingInvites = ref(false);
const loadInvitesError = ref('');
const inviteSearch = ref('');

// --------------------
// Histórico (inativos + convites revogados/expirados)
// --------------------
const history = ref([]);
const loadingHistory = ref(false);
const loadHistoryError = ref('');
const historySearch = ref('');

const HIGHLIGHT_MS = 24 * 60 * 60 * 1000;
function isRecent(row) {
    if (!row?.created_at) return false;
    return Date.now() - new Date(row.created_at).getTime() < HIGHLIGHT_MS;
}

const filteredHistory = computed(() => {
    const q = (historySearch.value || '').trim().toLowerCase();
    const base = history.value || [];
    if (!q) return base;
    return base.filter((h) => {
        const a = (h.full_name || '').toLowerCase();
        const b = (h.email || '').toLowerCase();
        return a.includes(q) || b.includes(q);
    });
});

// --------------------
// Meus vínculos (visão do terapeuta logado)
// --------------------
const myLinks = ref([]);
const loadingMyLinks = ref(false);
const loadMyLinksError = ref('');

// --------------------
// QA: auth users (view temporária)
// --------------------
const allUsers = ref([]);
const loadingUsers = ref(false);
const loadUsersError = ref('');

// ======================================================
// Tenant Context
// ======================================================
const tenantId = computed(() => tenantStore.activeTenantId || null);

const effectiveRole = computed(() => tenantStore.role || tenantStore.activeRole || tenantStore.currentRole || tenantStore.activeRoleNormalized || '');

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

const activeTenantKind = ref(null);

const canManage = computed(() => {
    const r = (effectiveRole.value || '').toString();
    const isAdmin = r === 'clinic_admin' || r === 'tenant_admin';
    if (!isAdmin) return false;
    // Aceita qualquer kind de clínica: 'clinic', 'clinic_coworking', 'clinic_reception', 'clinic_full'
    // Se activeTenantKind ainda não carregou (null), confia no role já normalizado
    const k = String(activeTenantKind.value || '');
    if (!k) return true;
    return k === 'clinic' || k.startsWith('clinic_');
});

const DEV_TEST_EMAILS = ['therapist2@agenciapsi.com.br', 'therapist3@agenciapsi.com.br', 'secretary@agenciapsi.com.br'];

const devInviteLinks = computed(() => {
    return DEV_TEST_EMAILS.map((email) => {
        const invite = (invites.value || []).find((i) => (i.email || '').toLowerCase() === email.toLowerCase());
        return {
            email,
            token: invite?.token || null
        };
    });
});

const invite = ref({
    open: false,
    type: 'therapist',
    email: '',
    loading: false,
    error: ''
});

const inviteHeader = computed(() => (invite.value.type === 'therapist' ? 'Convidar terapeuta' : 'Adicionar secretária'));

function normalizeRoleLabel(role) {
    if (role === 'tenant_admin') return 'clinic_admin';
    return role;
}

function roleSeverity(role) {
    if (role === 'tenant_admin') return 'info';
    if (role === 'therapist') return 'success';
    if (role === 'secretary') return 'warning';
    return 'secondary';
}

function roleSort(role) {
    if (role === 'tenant_admin') return 1;
    if (role === 'therapist') return 2;
    if (role === 'secretary') return 3;
    return 9;
}

const filteredMembers = computed(() => {
    const q = (search.value || '').trim().toLowerCase();
    const base = members.value || [];
    if (!q) return base;
    return base.filter((m) => {
        const a = (m.full_name || '').toLowerCase();
        const b = (m.email || '').toLowerCase();
        return a.includes(q) || b.includes(q);
    });
});

const filteredInvites = computed(() => {
    const q = (inviteSearch.value || '').trim().toLowerCase();
    const base = invites.value || [];
    if (!q) return base;
    return base.filter((i) => (i.email || '').toLowerCase().includes(q));
});

function formatDate(v) {
    if (!v) return '-';
    try {
        const d = new Date(v);
        if (Number.isNaN(d.getTime())) return String(v);
        return d.toLocaleString('pt-BR');
    } catch {
        return String(v);
    }
}

function openAcceptInviteDemo() {
    window.open('/accept-invite', '_blank', 'noopener,noreferrer');
}

function openLogin() {
    window.open('/auth/login', '_blank', 'noopener,noreferrer');
}

// ======================================================
// Helpers
// ======================================================
function normalizeEmail(v) {
    return String(v || '')
        .trim()
        .toLowerCase();
}

function isSchemaCacheError(e) {
    const msg = String(e?.message || e || '');
    return msg.toLowerCase().includes('schema cache') || msg.toLowerCase().includes('could not find the function');
}

function isSelfInviteError(e) {
    const msg = String(e?.message || e || '').toLowerCase();
    return msg.includes('não pode') && msg.includes('próprio') && msg.includes('email');
}

// ======================================================
// Loaders
// ======================================================
async function loadMembers() {
    loadError.value = '';
    if (!tenantId.value) return;

    loading.value = true;
    try {
        const { data, error } = await supabase
            .from('v_tenant_members_with_profiles')
            .select('tenant_id,user_id,role,status,created_at,full_name,email')
            .eq('tenant_id', tenantId.value)
            .in('role', ['tenant_admin', 'therapist', 'secretary'])
            .eq('status', 'active')
            .order('created_at', { ascending: true });

        if (error) throw error;

        const { data: authData } = await supabase.auth.getUser();
        const myUid = authData?.user?.id || null;

        members.value = (data || []).map((row) => ({
            tenant_id: row.tenant_id,
            user_id: row.user_id,
            role: row.role,
            role_label: normalizeRoleLabel(row.role),
            role_sort: roleSort(row.role),
            status: row.status,
            full_name: row.full_name,
            email: row.email,
            is_self: myUid && row.user_id === myUid
        }));

        await loadClinicNamesForMembers();
    } catch (err) {
        console.error(err);
        loadError.value = err?.message || 'Falha ao carregar profissionais.';
    } finally {
        loading.value = false;
    }
}

async function loadInvites() {
    loadInvitesError.value = '';
    if (!tenantId.value) return;

    loadingInvites.value = true;
    try {
        const { data, error } = await supabase
            .from('tenant_invites')
            .select('tenant_id,email,role,token,created_at,expires_at,accepted_at,revoked_at')
            .eq('tenant_id', tenantId.value)
            .is('accepted_at', null)
            .is('revoked_at', null)
            .order('created_at', { ascending: false });

        if (error) throw error;
        invites.value = data || [];
    } catch (err) {
        console.error(err);
        loadInvitesError.value = err?.message || 'Falha ao carregar convites.';
    } finally {
        loadingInvites.value = false;
    }
}

async function loadHistory() {
    loadHistoryError.value = '';
    if (!tenantId.value) return;

    loadingHistory.value = true;
    try {
        // membros inativos
        const { data: inactiveMembers, error: e1 } = await supabase
            .from('v_tenant_members_with_profiles')
            .select('tenant_id,user_id,role,status,created_at,full_name,email')
            .eq('tenant_id', tenantId.value)
            .in('role', ['tenant_admin', 'therapist', 'secretary'])
            .eq('status', 'inactive')
            .order('created_at', { ascending: false });

        if (e1) throw e1;

        // convites revogados ou expirados
        const { data: oldInvites, error: e2 } = await supabase
            .from('tenant_invites')
            .select('tenant_id,email,role,token,created_at,expires_at,accepted_at,revoked_at,revoked_by')
            .eq('tenant_id', tenantId.value)
            .or('revoked_at.not.is.null,expires_at.lt.' + new Date().toISOString())
            .is('accepted_at', null)
            .order('created_at', { ascending: false });

        if (e2) throw e2;

        const membersFormatted = (inactiveMembers || []).map((m) => ({
            kind: 'member',
            tenant_id: m.tenant_id,
            user_id: m.user_id,
            full_name: m.full_name,
            email: m.email,
            role: m.role,
            role_label: normalizeRoleLabel(m.role),
            status: m.status,
            created_at: m.created_at,
            revoked_at: null,
            expires_at: null,
            token: null
        }));

        const invitesFormatted = (oldInvites || []).map((i) => ({
            kind: i.revoked_at ? 'invite_revoked' : 'invite_expired',
            tenant_id: i.tenant_id,
            user_id: null,
            full_name: null,
            email: i.email,
            role: i.role,
            role_label: i.role,
            status: i.revoked_at ? 'revogado' : 'expirado',
            created_at: i.created_at,
            revoked_at: i.revoked_at,
            expires_at: i.expires_at,
            token: i.token
        }));

        history.value = [...membersFormatted, ...invitesFormatted].sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
    } catch (err) {
        console.error(err);
        loadHistoryError.value = err?.message || 'Falha ao carregar histórico.';
    } finally {
        loadingHistory.value = false;
    }
}

async function loadMyLinks() {
    loadMyLinksError.value = '';
    loadingMyLinks.value = true;
    try {
        const { data: authData } = await supabase.auth.getUser();
        const myUid = authData?.user?.id || null;
        if (!myUid) return;

        const { data, error } = await supabase.from('tenant_members').select('tenant_id, role, status, created_at, tenants(name, kind)').eq('user_id', myUid).eq('status', 'active').order('created_at', { ascending: true });

        if (error) throw error;

        // só mostra clínicas (kind = 'clinic'), ignora tenant pessoal (saas)
        myLinks.value = (data || [])
            .filter((r) => r.tenants?.kind === 'clinic')
            .map((r) => ({
                tenant_id: r.tenant_id,
                clinic_name: r.tenants?.name || 'Clínica sem nome',
                role: r.role,
                role_label: normalizeRoleLabel(r.role),
                status: r.status,
                created_at: r.created_at
            }));
    } catch (err) {
        console.error(err);
        loadMyLinksError.value = err?.message || 'Falha ao carregar vínculos.';
    } finally {
        loadingMyLinks.value = false;
    }
}

// carrega nomes das clínicas para exibir na coluna Vínculo
async function loadClinicNamesForMembers() {
    if (!tenantId.value) return;
    try {
        const ids = [...new Set([tenantId.value, ...(members.value || []).map((m) => m.tenant_id).filter(Boolean)])];

        const { data, error } = await supabase.from('tenants').select('id, name, kind').in('id', ids);

        if (error) throw error;
        const map = {};
        (data || []).forEach((t) => {
            map[t.id] = t.name || 'Clínica sem nome';
            if (t.id === tenantId.value) {
                activeTenantKind.value = t.kind;
            }
        });
        clinicNamesMap.value = { ...clinicNamesMap.value, ...map };
    } catch (err) {
        console.error('[loadClinicNamesForMembers]', err);
    }
}

async function loadAllUsers() {
    loadingUsers.value = true;
    loadUsersError.value = '';

    try {
        const { data, error } = await supabase.from('v_auth_users_public').select('user_id,email,created_at,last_sign_in_at').order('created_at', { ascending: false }).limit(100);

        if (error) throw error;
        allUsers.value = data || [];
    } catch (err) {
        console.error(err);
        loadUsersError.value = err?.message || 'Falha ao carregar usuários.';
    } finally {
        loadingUsers.value = false;
    }
}

// ======================================================
// Invite actions (Modelo B)
// ======================================================
function openInvite(type) {
    invite.value.open = true;
    invite.value.type = type;
    invite.value.email = '';
    invite.value.loading = false;
    invite.value.error = '';
}

async function submitInvite() {
    invite.value.error = '';
    if (!tenantId.value) {
        invite.value.error = 'Tenant não definido.';
        return;
    }

    const email = normalizeEmail(invite.value.email);
    if (!email) {
        invite.value.error = 'Informe um email.';
        return;
    }

    invite.value.loading = true;
    try {
        // ✅ Modelo B: RPC nova (sem fallback)
        // Observação: returns uuid (token). A gente não precisa dele aqui, mas pode usar depois.
        const { data, error } = await supabase.rpc('tenant_invite_member_by_email', {
            p_tenant_id: tenantId.value,
            p_email: email,
            p_role: invite.value.type
        });

        if (error) throw error;

        toast.add({
            severity: 'success',
            summary: 'Convite criado',
            detail: `Convite criado para ${email} como ${invite.value.type}.`,
            life: 3500
        });

        // se quiser, dá pra usar o token retornado:
        // console.log('invite token:', data)

        invite.value.open = false;
        await loadInvites();
    } catch (err) {
        console.error(err);

        if (isSchemaCacheError(err)) {
            invite.value.error = "O backend foi atualizado, mas o schema cache da API ainda não recarregou. Rode no Supabase SQL Editor: notify pgrst, 'reload schema';";
        } else if (isSelfInviteError(err)) {
            invite.value.error = err?.message || 'Você não pode convidar o seu próprio email.';
        } else {
            invite.value.error = err?.message || 'Falha ao criar convite.';
        }
    } finally {
        invite.value.loading = false;
    }
}

async function copyInviteLink(row) {
    try {
        const origin = window.location.origin;
        const url = `${origin}/accept-invite?token=${row.token}`;
        await navigator.clipboard.writeText(url);
        toast.add({ severity: 'success', summary: 'Link copiado', detail: 'Link do convite copiado para a área de transferência.', life: 2500 });
    } catch (e) {
        console.error(e);
        toast.add({ severity: 'warn', summary: 'Falha ao copiar', detail: 'Não foi possível copiar automaticamente. Copie o token manualmente.', life: 3500 });
    }
}

async function resendPendingInvite(row) {
    if (!tenantId.value) return;
    if (!row?.email) return;

    try {
        const email = normalizeEmail(row.email);
        const role = row.role || 'therapist';

        // ✅ RPC nova (sem fallback)
        const { error } = await supabase.rpc('tenant_invite_member_by_email', {
            p_tenant_id: tenantId.value,
            p_email: email,
            p_role: role
        });
        if (error) throw error;

        toast.add({
            severity: 'success',
            summary: 'Convite reenviado',
            detail: `Novo convite gerado para ${email}.`,
            life: 3500
        });

        await loadInvites();
    } catch (err) {
        console.error(err);
        const msg = isSchemaCacheError(err) ? "Schema cache da API ainda não recarregou. Rode: notify pgrst, 'reload schema';" : err?.message || 'Não foi possível reenviar.';
        toast.add({ severity: 'error', summary: 'Falha ao reenviar', detail: msg, life: 4500 });
    }
}

function confirmRevokeInvite(row) {
    confirm.require({
        header: 'Revogar convite',
        message: `Revogar o convite de ${row.email}?`,
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-danger',
        acceptLabel: 'Revogar',
        rejectLabel: 'Cancelar',
        accept: async () => {
            await revokeInviteNow(row);
        }
    });
}

async function revokeInviteNow(row) {
    if (!tenantId.value) return;
    if (!row?.token) return;

    try {
        // ⚠️ Pode falhar com RLS (ideal: RPC SECURITY DEFINER tenant_revoke_invite).
        const { data: authData } = await supabase.auth.getUser();
        const myUid = authData?.user?.id || null;

        const { error } = await supabase
            .from('tenant_invites')
            .update({
                revoked_at: new Date().toISOString(),
                revoked_by: myUid
            })
            .eq('tenant_id', tenantId.value)
            .eq('token', row.token)
            .is('accepted_at', null)
            .is('revoked_at', null);

        if (error) throw error;

        toast.add({ severity: 'success', summary: 'Convite revogado', detail: 'O convite foi revogado.', life: 3000 });
        await loadInvites();
    } catch (err) {
        console.error(err);
        toast.add({
            severity: 'error',
            summary: 'Falha ao revogar',
            detail: err?.message || 'Não foi possível revogar. Se o RLS bloquear, crie RPC tenant_revoke_invite.',
            life: 5200
        });
    }
}

// ======================================================
// Equipe actions
// ======================================================
function confirmRemove(member) {
    confirm.require({
        header: 'Desvincular profissional',
        message: 'Isso irá desativar o vínculo com a clínica. (Por enquanto não bloqueamos por atendimentos agendados; essa regra será aplicada quando a agenda registrar o terapeuta no evento.)',
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-danger',
        acceptLabel: 'Desvincular',
        rejectLabel: 'Cancelar',
        accept: async () => {
            await removeMember(member);
        }
    });
}

async function removeMember(member) {
    if (!tenantId.value) return;

    try {
        // mantém o RPC principal com prefixo
        const { error } = await supabase.rpc('tenant_remove_member_soft', {
            p_tenant_id: tenantId.value,
            p_member_user_id: member.user_id
        });
        if (error) throw error;

        toast.add({
            severity: 'success',
            summary: 'Vínculo desativado',
            detail: 'O profissional foi desvinculado (status inativo).',
            life: 3500
        });

        await loadMembers();
        await loadHistory();
    } catch (err) {
        console.error(err);
        toast.add({
            severity: 'error',
            summary: 'Falha ao desvincular',
            detail: err?.message || 'Não foi possível desvincular.',
            life: 4500
        });
    }
}

async function reactivateMember(member) {
    if (!tenantId.value) return;

    try {
        const { error } = await supabase.rpc('tenant_reactivate_member', {
            p_tenant_id: tenantId.value,
            p_member_user_id: member.user_id
        });
        if (error) throw error;

        toast.add({
            severity: 'success',
            summary: 'Vínculo reativado',
            detail: 'O profissional voltou para ativo.',
            life: 3500
        });

        await loadMembers();
        await loadHistory();
    } catch (err) {
        console.error(err);
        toast.add({
            severity: 'error',
            summary: 'Falha ao reativar',
            detail: err?.message || 'Não foi possível reativar.',
            life: 4500
        });
    }
}

function resendInvite(member) {
    confirm.require({
        header: 'Notificar por email',
        message: `Enviar notificação para ${member.email}? (Fluxo legado; Modelo B usa Convites)`,
        icon: 'pi pi-envelope',
        acceptLabel: 'Enviar',
        rejectLabel: 'Cancelar',
        accept: async () => {
            await resendInviteNow(member);
        }
    });
}

async function resendInviteNow(member) {
    if (!tenantId.value) return;
    if (!member?.email) {
        toast.add({ severity: 'warn', summary: 'Sem email', detail: 'Este usuário não possui email.', life: 3000 });
        return;
    }

    try {
        // Legado (mantenha só enquanto você não criar tenant_resend_invite).
        const safeRole = member.role === 'tenant_admin' ? 'therapist' : member.role;

        const { error } = await supabase.rpc('tenant_add_member_by_email', {
            p_tenant_id: tenantId.value,
            p_email: normalizeEmail(member.email),
            p_role: safeRole
        });
        if (error) throw error;

        toast.add({
            severity: 'success',
            summary: 'Notificação enviada',
            detail: `Ação registrada para ${member.email}. (Fluxo legado: pode reativar automaticamente.)`,
            life: 4200
        });

        await loadMembers();
    } catch (err) {
        console.error(err);
        toast.add({
            severity: 'error',
            summary: 'Falha ao notificar',
            detail: err?.message || 'Não foi possível enviar/registrar a notificação.',
            life: 4500
        });
    }
}

// ======================================================
// Boot
// ======================================================
watch(
    () => tenantId.value,
    async (v) => {
        if (!v) return;
        await loadMembers();
        await loadInvites();
        await loadHistory();
        await loadMyLinks();
    },
    { immediate: true }
);

onMounted(async () => {
    if (!tenantStore.loaded && !tenantStore.loading) {
        await tenantStore.loadSessionAndTenant();
    }
    await loadAllUsers();
});
</script>

<template>
    <ConfirmDialog />

    <!-- 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)]">Profissionais da clínica</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Gerencie terapeutas e secretarias vinculados ao seu tenant.</div>
                </div>

                <div class="flex items-center gap-2 flex-wrap shrink-0">
                    <Button label="Convidar terapeuta" icon="pi pi-user-plus" @click="openInvite('therapist')" :disabled="!tenantReady || !canManage" />
                    <Button label="Adicionar secretária" icon="pi pi-users" severity="secondary" outlined @click="openInvite('secretary')" :disabled="!tenantReady || !canManage" />
                </div>
            </div>

            <!-- Loading leve do tenant -->
            <div v-if="!tenantReady" class="text-[1rem] text-[var(--text-color-secondary)] opacity-70">Carregando permissões da clínica…</div>

            <!-- Aviso de permissão (somente se carregou e não tem permissão) -->
            <div v-else-if="!canManage" class="text-[1rem] text-orange-600">Sua conta não tem permissão para gerenciar profissionais (apenas <b>clinic_admin</b>).</div>

            <!-- Debug (opcional) -->
            <div v-if="debug" class="text-[1rem] opacity-70">tenantId={{ tenantId }} | role={{ effectiveRole || '(vazio)' }} | canManage={{ canManage }}</div>
        </div>
    </div>

    <div class="px-3 md:px-4 pb-8 flex flex-col gap-4">
        <!-- 🔎 Aviso sobre logins de teste + atalhos de convite -->
        <div class="overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)]">
            <div class="p-5 md:p-6">
                <div class="flex items-start gap-3">
                    <div class="h-10 w-10 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] grid place-items-center shrink-0">
                        <i class="pi pi-info-circle opacity-70" />
                    </div>

                    <div class="min-w-0 flex-1">
                        <div class="font-semibold text-base leading-tight">Logins de teste (ambiente de desenvolvimento)</div>

                        <div class="text-[1rem] opacity-80 mt-1 leading-relaxed">
                            As credenciais fixas para testes (clinic, therapist, therapist2, therapist3, secretary, patient e saas) estão disponíveis na tela inicial do sistema (<span class="font-mono">HomeCards</span>).
                        </div>

                        <div class="text-[1rem] opacity-80 mt-2 leading-relaxed">Para utilizá-las, basta realizar <b>logout da sessão atual</b> e selecionar o perfil desejado na tela inicial.</div>

                        <!-- ✅ Atalhos: abrir dialog e já preencher o email -->
                        <div class="mt-4 flex flex-wrap items-center gap-2">
                            <span class="text-[1rem] opacity-70 mr-1">Atalhos (DEV):</span>

                            <Button label="Convidar therapist2" icon="pi pi-user-plus" severity="secondary" outlined size="small" :disabled="!tenantReady || !canManage" @click="openInvitePrefill('therapist2@agenciapsi.com.br', 'therapist')" />

                            <Button label="Convidar therapist3" icon="pi pi-user-plus" severity="secondary" outlined size="small" :disabled="!tenantReady || !canManage" @click="openInvitePrefill('therapist3@agenciapsi.com.br', 'therapist')" />

                            <Button label="Convidar secretary" icon="pi pi-users" severity="secondary" outlined size="small" :disabled="!tenantReady || !canManage" @click="openInvitePrefill('secretary@agenciapsi.com.br', 'secretary')" />
                        </div>

                        <!-- Links de convite pendentes para testes -->
                        <div class="mt-3 flex flex-col gap-1">
                            <span class="text-[1rem] opacity-70 mb-1">Links de convite pendentes (DEV):</span>
                            <div v-for="item in devInviteLinks" :key="item.email" class="flex items-center gap-2 flex-wrap">
                                <span class="text-[1rem] font-mono opacity-70 w-56 truncate">{{ item.email }}</span>
                                <Button label="Copiar link de convite" icon="pi pi-copy" severity="secondary" outlined size="small" :disabled="!item.token" @click="copyInviteLink(item)" />
                                <span v-if="!item.token" class="text-[1rem] opacity-50 italic">sem convite pendente</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- ✅ DOCUMENTAÇÃO INTERNA (visível na tela, para QA) -->
        <div class="overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)]">
            <div class="p-5 md:p-6">
                <div class="flex items-start gap-3">
                    <div class="h-10 w-10 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] grid place-items-center shrink-0">
                        <i class="pi pi-book opacity-70" />
                    </div>

                    <div class="min-w-0">
                        <div class="font-semibold text-lg leading-tight">Guia rápido — Convites (Modelo B) e como testar</div>
                        <div class="text-[1rem] opacity-80 mt-1 leading-relaxed">
                            Esta área existe para facilitar o QA/validação do fluxo de convites no SaaS multi-tenant. A tela pública de aceite está em:
                            <span class="font-mono">/accept-invite?token=&lt;uuid&gt;</span>. O login fica em <span class="font-mono">/auth/login</span>.
                        </div>

                        <div class="mt-4 grid gap-3">
                            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-4">
                                <div class="font-semibold text-[1rem] mb-2">Rotas e comportamento esperado</div>
                                <ul class="text-[1rem] opacity-80 leading-relaxed list-disc pl-5 space-y-1">
                                    <li><b>Aceite público:</b> <span class="font-mono">/accept-invite?token=&lt;uuid&gt;</span></li>
                                    <li><b>Login:</b> <span class="font-mono">/auth/login</span></li>
                                    <li>
                                        <b>Se NÃO logado:</b> salva token em <span class="font-mono">sessionStorage(pending_invite_token_v1)</span>
                                        → redireciona para login → após login retoma o aceite automaticamente.
                                    </li>
                                    <li><b>Se logado:</b> chama RPC <span class="font-mono">tenant_accept_invite(p_token)</span> → sucesso: cria/ativa membership → redireciona para <span class="font-mono">/admin</span>.</li>
                                    <li><b>Erros esperados:</b> token inválido/expirado, convite já usado, e-mail diferente (mismatch).</li>
                                </ul>

                                <div class="mt-3 text-[1rem] opacity-70 leading-relaxed">
                                    <b>Nota:</b> o backend foi corrigido para não depender do claim de email no JWT (erro antigo <span class="font-mono">missing_email_claim</span>). O email é resolvido via
                                    <span class="font-mono">auth.users</span> usando <span class="font-mono">SECURITY DEFINER</span>.
                                </div>
                            </div>

                            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-4">
                                <div class="font-semibold text-[1rem] mb-2">Como testar (prático)</div>
                                <ol class="text-[1rem] opacity-80 leading-relaxed list-decimal pl-5 space-y-1">
                                    <li>Convidar alguém nesta tela (botões acima).</li>
                                    <li>Abrir a aba <b>Convites</b> e copiar o link.</li>
                                    <li>Abrir o link em aba anônima → logar com o mesmo email → aceitar.</li>
                                    <li>Voltar aqui: a pessoa sai de <b>Convites</b> e aparece em <b>Equipe</b>.</li>
                                </ol>
                            </div>
                        </div>

                        <div class="mt-4 flex flex-wrap gap-2">
                            <Button label="Abrir /accept-invite (sem token)" icon="pi pi-external-link" severity="secondary" outlined @click="openAcceptInviteDemo()" />
                            <Button label="Abrir /auth/login" icon="pi pi-sign-in" severity="secondary" outlined @click="openLogin()" />
                        </div>

                        <div class="mt-2 text-[1rem] opacity-70">Dica: use aba anônima para testar o fluxo completo sem interferência de sessão.</div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Abas -->
        <TabView class="rounded-md overflow-hidden">
            <!-- =========================
           ABA 1: EQUIPE
           ========================= -->
            <TabPanel header="Equipe">
                <div class="grid grid-cols-1 gap-4">
                    <Card class="rounded-md">
                        <template #title>
                            <div class="flex items-center justify-between gap-3 flex-wrap">
                                <div class="min-w-0">
                                    <div class="font-semibold">Equipe</div>
                                    <div class="text-[1rem] opacity-70">Membros ativos/inativos do tenant (somente <b>tenant_members</b>).</div>
                                </div>

                                <div class="flex items-center gap-2 flex-wrap justify-end">
                                    <div class="w-full md:w-80">
                                        <FloatLabel variant="on" class="w-full">
                                            <IconField class="w-full">
                                                <InputIcon class="pi pi-search" />
                                                <InputText v-model="search" id="team_search" class="w-full pr-10" variant="filled" />
                                            </IconField>
                                            <label for="team_search">Buscar por nome ou email</label>
                                        </FloatLabel>
                                    </div>

                                    <Button icon="pi pi-refresh" severity="secondary" outlined :loading="loading" @click="loadMembers" aria-label="Recarregar" :disabled="!tenantReady" />
                                </div>
                            </div>
                        </template>

                        <template #content>
                            <div v-if="loadError" class="mb-3 rounded-md border border-red-200 bg-red-50 p-3 text-red-700 text-[1rem]">
                                {{ loadError }}
                            </div>

                            <DataTable
                                :value="filteredMembers"
                                :loading="loading"
                                dataKey="user_id"
                                responsiveLayout="scroll"
                                class="p-datatable-sm prof-datatable"
                                sortField="role_sort"
                                :sortOrder="1"
                                :rowClass="(r) => (isRecent(r) ? 'row-new-highlight' : '')"
                            >
                                <Column header="Pessoa" style="min-width: 18rem">
                                    <template #body="{ data }">
                                        <div class="flex items-center gap-3 min-w-0">
                                            <div class="h-10 w-10 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] grid place-items-center">
                                                <i class="pi pi-user opacity-70" />
                                            </div>

                                            <div class="min-w-0">
                                                <div class="font-semibold truncate">
                                                    {{ data.full_name || 'Sem nome' }}
                                                </div>

                                                <div class="text-[1rem] opacity-70 truncate">
                                                    {{ data.email || 'Sem email' }}
                                                </div>

                                                <div class="text-[1rem] opacity-60 font-mono truncate">tenant: {{ data.tenant_id }}</div>

                                                <div class="text-[1rem] opacity-60 font-mono truncate">uid: {{ data.user_id }}</div>
                                            </div>
                                        </div>
                                    </template>
                                </Column>

                                <Column field="role_label" header="Papel" style="width: 14rem">
                                    <template #body="{ data }">
                                        <Tag :value="data.role_label" :severity="roleSeverity(data.role)" rounded />
                                    </template>
                                </Column>

                                <Column field="status" header="Status" style="width: 10rem">
                                    <template #body="{ data }">
                                        <Tag :value="data.status" :severity="data.status === 'active' ? 'success' : 'secondary'" rounded />
                                    </template>
                                </Column>

                                <Column header="Vínculo" style="min-width: 12rem">
                                    <template #body="{ data }">
                                        <span v-if="canManage" class="text-[1rem] opacity-70 italic">vinculado nesta clínica</span>
                                        <template v-else>
                                            <div v-if="myLinks.length > 0" class="flex flex-col gap-1">
                                                <span v-for="link in myLinks" :key="link.tenant_id" class="text-[1rem]">{{ link.clinic_name }}</span>
                                            </div>
                                            <span v-else class="text-[1rem] opacity-50">—</span>
                                        </template>
                                    </template>
                                </Column>

                                <Column header="Ações" style="width: 16rem" bodyClass="text-right">
                                    <template #body="{ data }">
                                        <div class="flex justify-end gap-2 flex-wrap">
                                            <Button v-if="data.status === 'active'" label="Desvincular" icon="pi pi-times" severity="danger" outlined size="small" :disabled="!tenantReady || !canManage || data.is_self" @click="confirmRemove(data)" />

                                            <Button label="Notificar por email" icon="pi pi-send" severity="secondary" outlined size="small" :disabled="!tenantReady || !canManage || !data.email" @click="resendInvite(data)" />
                                        </div>

                                        <div v-if="data.is_self" class="text-[1rem] opacity-60 mt-1 text-right">Você</div>
                                    </template>
                                </Column>

                                <template #empty>
                                    <div class="py-8 text-center opacity-70">Nenhum profissional encontrado.</div>
                                </template>
                            </DataTable>

                            <div class="text-[1rem] block mt-3 opacity-70">
                                Papel real salvo em <span class="font-mono">tenant_members.role</span>: <b>tenant_admin</b>, <b>therapist</b>, <b>secretary</b>, <b>patient</b>. No front, normalizamos <b>tenant_admin → clinic_admin</b> (apenas para
                                UI).
                            </div>

                            <div class="text-[1rem] block mt-2 opacity-70"><b>Status:</b> <span class="font-mono">active</span> = acesso liberado. <span class="font-mono">inactive</span> = vínculo desativado (histórico).</div>
                        </template>
                    </Card>

                    <!-- Meus Vínculos (visível apenas para terapeutas e secretárias) -->
                    <Card v-if="(effectiveRole === 'therapist' || effectiveRole === 'secretary') && (myLinks.length > 0 || loadingMyLinks)" class="rounded-md">
                        <template #title>
                            <div class="flex items-center justify-between gap-3 flex-wrap">
                                <div class="min-w-0">
                                    <div class="font-semibold">Meus vínculos</div>
                                    <div class="text-[1rem] opacity-70">Clínicas às quais sua conta está associada.</div>
                                </div>
                                <Button icon="pi pi-refresh" severity="secondary" outlined :loading="loadingMyLinks" @click="loadMyLinks" aria-label="Recarregar meus vínculos" />
                            </div>
                        </template>

                        <template #content>
                            <div v-if="loadMyLinksError" class="mb-3 rounded-md border border-red-200 bg-red-50 p-3 text-red-700 text-[1rem]">
                                {{ loadMyLinksError }}
                            </div>

                            <div class="grid gap-3">
                                <div v-for="link in myLinks" :key="link.tenant_id" class="flex items-center justify-between gap-4 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-4">
                                    <div class="flex items-center gap-3 min-w-0">
                                        <div class="h-10 w-10 rounded-md border border-[var(--surface-border)] bg-[color-mix(in_srgb,var(--surface-card),transparent_30%)] grid place-items-center shrink-0">
                                            <i class="pi pi-building opacity-70" />
                                        </div>
                                        <div class="min-w-0">
                                            <div class="font-semibold truncate">{{ link.clinic_name }}</div>
                                            <div class="text-[1rem] font-mono opacity-50 truncate">{{ link.tenant_id }}</div>
                                        </div>
                                    </div>

                                    <div class="flex items-center gap-2 shrink-0">
                                        <Tag :value="link.role_label" :severity="roleSeverity(link.role)" rounded />
                                        <Tag :value="link.status === 'active' ? 'ativo' : 'inativo'" :severity="link.status === 'active' ? 'success' : 'secondary'" rounded />
                                    </div>
                                </div>
                            </div>

                            <div class="text-[1rem] block mt-3 opacity-70">Um profissional pode estar vinculado a múltiplas clínicas simultaneamente.</div>
                        </template>
                    </Card>
                </div>
            </TabPanel>
            ========================= -->
            <TabPanel header="Convites">
                <div class="grid grid-cols-1 gap-4">
                    <Card class="rounded-md">
                        <template #title>
                            <div class="flex items-center justify-between gap-3 flex-wrap">
                                <div class="min-w-0">
                                    <div class="font-semibold">Convites pendentes</div>
                                    <div class="text-[1rem] opacity-70">Convites do tenant que ainda não foram aceitos (tabela <b>tenant_invites</b>).</div>
                                </div>

                                <div class="flex items-center gap-2 flex-wrap justify-end">
                                    <div class="w-full md:w-80">
                                        <FloatLabel variant="on" class="w-full">
                                            <IconField class="w-full">
                                                <InputIcon class="pi pi-search" />
                                                <InputText v-model="inviteSearch" id="invite_search" class="w-full pr-10" variant="filled" />
                                            </IconField>
                                            <label for="invite_search">Buscar por email</label>
                                        </FloatLabel>
                                    </div>

                                    <Button icon="pi pi-refresh" severity="secondary" outlined :loading="loadingInvites" @click="loadInvites" aria-label="Recarregar convites" :disabled="!tenantReady" />
                                </div>
                            </div>
                        </template>

                        <template #content>
                            <div v-if="loadInvitesError" class="mb-3 rounded-md border border-red-200 bg-red-50 p-3 text-red-700 text-[1rem]">
                                {{ loadInvitesError }}
                            </div>

                            <DataTable
                                :value="filteredInvites"
                                :loading="loadingInvites"
                                dataKey="token"
                                responsiveLayout="scroll"
                                class="p-datatable-sm invites-datatable"
                                sortField="created_at"
                                :sortOrder="-1"
                                :rowClass="(r) => (isRecent(r) ? 'row-new-highlight' : '')"
                            >
                                <Column header="Email" style="min-width: 18rem">
                                    <template #body="{ data }">
                                        <div class="min-w-0">
                                            <div class="font-semibold truncate">{{ data.email }}</div>
                                            <div class="text-[1rem] opacity-60 font-mono truncate">token: {{ data.token }}</div>
                                            <div class="text-[1rem] opacity-60 font-mono truncate">tenant: {{ data.tenant_id }}</div>
                                        </div>
                                    </template>
                                </Column>

                                <Column header="Papel" style="width: 12rem">
                                    <template #body="{ data }">
                                        <Tag :value="data.role" :severity="roleSeverity(data.role)" rounded />
                                    </template>
                                </Column>

                                <Column header="Expira" style="width: 14rem">
                                    <template #body="{ data }">
                                        <span class="text-[1rem] opacity-80">{{ formatDate(data.expires_at) }}</span>
                                    </template>
                                </Column>

                                <Column header="Criado em" style="width: 14rem">
                                    <template #body="{ data }">
                                        <span class="text-[1rem] opacity-80">{{ formatDate(data.created_at) }}</span>
                                    </template>
                                </Column>

                                <Column header="Ações" style="width: 20rem" bodyClass="text-right">
                                    <template #body="{ data }">
                                        <div class="flex justify-end gap-2 flex-wrap">
                                            <Button label="Copiar link" icon="pi pi-copy" severity="secondary" outlined size="small" :disabled="!data.token" @click="copyInviteLink(data)" />

                                            <Button label="Reenviar" icon="pi pi-refresh" severity="success" outlined size="small" :disabled="!tenantReady || !canManage" @click="resendPendingInvite(data)" />

                                            <Button label="Revogar" icon="pi pi-times" severity="danger" outlined size="small" :disabled="!tenantReady || !canManage" @click="confirmRevokeInvite(data)" />
                                        </div>
                                    </template>
                                </Column>

                                <template #empty>
                                    <div class="py-8 text-center opacity-70">Nenhum convite pendente.</div>
                                </template>
                            </DataTable>

                            <div class="text-[1rem] block mt-3 opacity-70"><b>Modelo B:</b> convidar não cria membership. O membership só aparece na aba <b>Equipe</b> após o aceite em <span class="font-mono">/accept-invite?token=...</span>.</div>
                        </template>
                    </Card>

                    <!-- QA TOOL: Auth Users (TEMPORÁRIO) -->
                    <Card class="rounded-md mt-2">
                        <template #title>
                            <div class="flex items-center justify-between">
                                <div class="font-semibold">Usuários cadastrados (Auth)</div>
                                <Button icon="pi pi-refresh" severity="secondary" outlined size="small" :loading="loadingUsers" @click="loadAllUsers" />
                            </div>
                        </template>

                        <template #content>
                            <div class="mb-4 rounded-md border border-orange-200 bg-orange-50 p-4">
                                <div class="flex gap-3">
                                    <i class="pi pi-exclamation-triangle mt-0.5 text-orange-600" />
                                    <div class="text-[1rem] text-orange-800 leading-relaxed">
                                        <div class="font-semibold mb-1">Aviso técnico — View temporária para testes (QA)</div>

                                        <div>Para permitir a listagem de usuários cadastrados no sistema, foi criada a view <span class="font-mono">public.v_auth_users_public</span>.</div>

                                        <div class="mt-2">
                                            Motivo: o schema <span class="font-mono">auth</span> não pode ser acessado diretamente pelo Supabase client (ex: <span class="font-mono">.from('auth.users')</span>). A view expõe apenas campos necessários
                                            para QA (email/uid/datas).
                                        </div>

                                        <div class="mt-2">⚠️ Remover após validação:</div>

                                        <div class="mt-2 font-mono text-[1rem] bg-white/60 border border-orange-200 rounded-md p-2">drop view if exists public.v_auth_users_public;</div>
                                    </div>
                                </div>
                            </div>

                            <div v-if="loadUsersError" class="mb-3 rounded-md border border-red-200 bg-red-50 p-3 text-red-700 text-[1rem]">
                                {{ loadUsersError }}
                            </div>

                            <DataTable :value="allUsers" :loading="loadingUsers" dataKey="user_id" responsiveLayout="scroll" class="p-datatable-sm">
                                <Column field="email" header="Email" style="min-width: 18rem" />
                                <Column header="User ID" style="min-width: 22rem">
                                    <template #body="{ data }">
                                        <span class="text-[1rem] font-mono opacity-70 break-all">{{ data.user_id }}</span>
                                    </template>
                                </Column>
                                <Column field="created_at" header="Criado em" />
                                <Column field="last_sign_in_at" header="Último login" />
                            </DataTable>
                        </template>
                    </Card>
                </div>
            </TabPanel>

            <!-- =========================
           ABA 3: HISTÓRICO
           ========================= -->
            <TabPanel header="Histórico">
                <div class="grid grid-cols-1 gap-4">
                    <Card class="rounded-md">
                        <template #title>
                            <div class="flex items-center justify-between gap-3 flex-wrap">
                                <div class="min-w-0">
                                    <div class="font-semibold">Histórico de desvinculados</div>
                                    <div class="text-[1rem] opacity-70">Membros inativos e convites revogados ou expirados deste tenant.</div>
                                </div>

                                <div class="flex items-center gap-2 flex-wrap justify-end">
                                    <div class="w-full md:w-80">
                                        <FloatLabel variant="on" class="w-full">
                                            <IconField class="w-full">
                                                <InputIcon class="pi pi-search" />
                                                <InputText v-model="historySearch" id="history_search" class="w-full pr-10" variant="filled" />
                                            </IconField>
                                            <label for="history_search">Buscar por nome ou email</label>
                                        </FloatLabel>
                                    </div>

                                    <Button icon="pi pi-refresh" severity="secondary" outlined :loading="loadingHistory" @click="loadHistory" aria-label="Recarregar histórico" :disabled="!tenantReady" />
                                </div>
                            </div>
                        </template>

                        <template #content>
                            <div v-if="loadHistoryError" class="mb-3 rounded-md border border-red-200 bg-red-50 p-3 text-red-700 text-[1rem]">
                                {{ loadHistoryError }}
                            </div>

                            <DataTable :value="filteredHistory" :loading="loadingHistory" dataKey="token" responsiveLayout="scroll" class="p-datatable-sm" sortField="created_at" :sortOrder="-1">
                                <Column header="Pessoa / Email" style="min-width: 18rem">
                                    <template #body="{ data }">
                                        <div class="flex items-center gap-3 min-w-0">
                                            <div class="h-10 w-10 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] grid place-items-center shrink-0">
                                                <i :class="data.kind === 'member' ? 'pi pi-user opacity-70' : 'pi pi-envelope opacity-70'" />
                                            </div>
                                            <div class="min-w-0">
                                                <div class="font-semibold truncate">{{ data.full_name || data.email || 'Sem identificação' }}</div>
                                                <div v-if="data.full_name" class="text-[1rem] opacity-70 truncate">{{ data.email }}</div>
                                                <div class="text-[1rem] opacity-50 font-mono truncate">
                                                    {{ data.kind === 'member' ? 'uid: ' + data.user_id : 'token: ' + data.token }}
                                                </div>
                                            </div>
                                        </div>
                                    </template>
                                </Column>

                                <Column header="Papel" style="width: 12rem">
                                    <template #body="{ data }">
                                        <Tag :value="data.role_label" :severity="roleSeverity(data.role)" rounded />
                                    </template>
                                </Column>

                                <Column header="Tipo" style="width: 12rem">
                                    <template #body="{ data }">
                                        <Tag :value="data.kind === 'member' ? 'Membro' : 'Convite'" :severity="data.kind === 'member' ? 'secondary' : 'warning'" rounded />
                                    </template>
                                </Column>

                                <Column header="Situação" style="width: 12rem">
                                    <template #body="{ data }">
                                        <Tag :value="data.status" :severity="data.status === 'revogado' ? 'danger' : 'secondary'" rounded />
                                    </template>
                                </Column>

                                <Column header="Data" style="width: 14rem">
                                    <template #body="{ data }">
                                        <div class="text-[1rem] opacity-80">
                                            <div>Criado: {{ formatDate(data.created_at) }}</div>
                                            <div v-if="data.revoked_at" class="text-[1rem] text-red-500 mt-0.5">Revogado: {{ formatDate(data.revoked_at) }}</div>
                                            <div v-else-if="data.expires_at && data.kind !== 'member'" class="text-[1rem] opacity-60 mt-0.5">Expirou: {{ formatDate(data.expires_at) }}</div>
                                        </div>
                                    </template>
                                </Column>

                                <Column header="Ações" style="width: 10rem" bodyClass="text-right">
                                    <template #body="{ data }">
                                        <Button v-if="data.kind === 'member'" label="Reativar" icon="pi pi-refresh" severity="success" outlined size="small" :disabled="!tenantReady || !canManage" @click="reactivateMember(data)" />
                                    </template>
                                </Column>

                                <template #empty>
                                    <div class="py-8 text-center opacity-70">Nenhum registro no histórico.</div>
                                </template>
                            </DataTable>

                            <div class="text-[1rem] block mt-3 opacity-70">Membros inativos podem ser reativados a qualquer momento. Convites revogados/expirados são apenas registro histórico.</div>
                        </template>
                    </Card>
                </div>
            </TabPanel>
        </TabView>

        <!-- Dialog: convite -->
        <Dialog v-model:visible="invite.open" modal dismissableMask :style="{ width: 'min(520px, 94vw)' }" :header="inviteHeader">
            <div class="space-y-4">
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">
                    Informe o email. Este fluxo cria um convite pendente (Modelo B) e só ativa o vínculo após o aceite em
                    <span class="font-mono">/accept-invite</span>.
                </div>

                <div class="grid gap-3">
                    <FloatLabel variant="on" class="w-full">
                        <IconField class="w-full">
                            <InputIcon class="pi pi-envelope" />
                            <InputText id="invite_email" v-model="invite.email" class="w-full" autocomplete="off" />
                        </IconField>
                        <label for="invite_email">Email</label>
                    </FloatLabel>
                </div>

                <div class="flex justify-end gap-2 pt-2">
                    <Button label="Cancelar" severity="secondary" outlined @click="invite.open = false" />
                    <Button label="Confirmar" icon="pi pi-check" :loading="invite.loading" :disabled="!invite.email || !tenantReady || !canManage" @click="submitInvite" />
                </div>

                <div v-if="invite.error" class="rounded-md border border-red-200 bg-red-50 p-3 text-[1rem] text-red-700">
                    {{ invite.error }}
                </div>
            </div>
        </Dialog>
    </div>
</template>

<style scoped>
.prof-datatable :deep(tr.row-new-highlight td) {
    background-color: #f0fdf4 !important;
}
.invites-datatable :deep(tr.row-new-highlight td) {
    background-color: #f0fdf4 !important;
}
:global(.app-dark) .prof-datatable :deep(tr.row-new-highlight td) {
    background-color: rgba(16, 185, 129, 0.08) !important;
}
:global(.app-dark) .invites-datatable :deep(tr.row-new-highlight td) {
    background-color: rgba(16, 185, 129, 0.08) !important;
}
</style>
