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

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

// ─── Estado ───────────────────────────────────────────────────────────────────
const slides = ref([]);
const loading = ref(false);
const saving = ref(false);
const previewIdx = ref(0);

const dialogOpen = ref(false);
const editingSlide = ref(null); // null = novo

const form = ref({ title: '', body: '', icon: '', ordem: 0, ativo: true });

// ─── Ícones disponíveis (subset PrimeIcons relevantes) ────────────────────────
const ICONS = [
    { value: 'pi-calendar-clock', label: 'Agenda' },
    { value: 'pi-users', label: 'Equipe' },
    { value: 'pi-globe', label: 'Online' },
    { value: 'pi-shield', label: 'Segurança' },
    { value: 'pi-heart-fill', label: 'Saúde' },
    { value: 'pi-chart-line', label: 'Estatísticas' },
    { value: 'pi-bell', label: 'Notificações' },
    { value: 'pi-lock', label: 'Privacidade' },
    { value: 'pi-mobile', label: 'Mobile' },
    { value: 'pi-sync', label: 'Sincronização' },
    { value: 'pi-star', label: 'Destaque' },
    { value: 'pi-check-circle', label: 'Aprovação' },
    { value: 'pi-comments', label: 'Comunicação' },
    { value: 'pi-file-edit', label: 'Prontuário' },
    { value: 'pi-briefcase', label: 'Profissional' },
    { value: 'pi-bolt', label: 'Performance' }
];

// ─── Computed ─────────────────────────────────────────────────────────────────
const slidesAtivos = computed(() => slides.value.filter((s) => s.ativo).sort((a, b) => a.ordem - b.ordem));
const previewSlide = computed(() => slidesAtivos.value[previewIdx.value] ?? slidesAtivos.value[0] ?? null);

// ─── Supabase ─────────────────────────────────────────────────────────────────
async function load() {
    loading.value = true;
    try {
        const { data, error } = await supabase.from('login_carousel_slides').select('*').order('ordem', { ascending: true });
        if (error) throw error;
        slides.value = data || [];
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao carregar slides.', life: 4000 });
    } finally {
        loading.value = false;
    }
}

function stripHtml(s) {
    return String(s || '')
        .replace(/<[^>]+>/g, '')
        .trim();
}

async function saveSlide() {
    if (!stripHtml(form.value.title) || !stripHtml(form.value.body)) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: 'Título e conteúdo são obrigatórios.', life: 3000 });
        return;
    }
    saving.value = true;
    try {
        const payload = {
            title: form.value.title,
            body: form.value.body,
            icon: form.value.icon || 'pi-star',
            ordem: form.value.ordem,
            ativo: form.value.ativo
        };
        if (editingSlide.value) {
            const { error } = await supabase.from('login_carousel_slides').update(payload).eq('id', editingSlide.value.id);
            if (error) throw error;
            toast.add({ severity: 'success', summary: 'Salvo', detail: 'Slide atualizado com sucesso.', life: 3000 });
        } else {
            const maxOrdem = slides.value.length ? Math.max(...slides.value.map((s) => s.ordem)) + 1 : 0;
            payload.ordem = maxOrdem;
            const { error } = await supabase.from('login_carousel_slides').insert(payload);
            if (error) throw error;
            toast.add({ severity: 'success', summary: 'Criado', detail: 'Slide adicionado com sucesso.', life: 3000 });
        }
        dialogOpen.value = false;
        await load();
        previewIdx.value = 0;
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao salvar.', life: 4000 });
    } finally {
        saving.value = false;
    }
}

async function toggleAtivo(slide) {
    try {
        const { error } = await supabase.from('login_carousel_slides').update({ ativo: !slide.ativo }).eq('id', slide.id);
        if (error) throw error;
        slide.ativo = !slide.ativo;
        toast.add({ severity: 'info', summary: slide.ativo ? 'Ativado' : 'Desativado', detail: `"${slide.title}"`, life: 2500 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message, life: 3000 });
    }
}

async function deleteSlide(slide) {
    confirm.require({
        message: `Remover o slide "${slide.title}"? Esta ação não pode ser desfeita.`,
        header: 'Confirmar remoção',
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-danger',
        acceptLabel: 'Remover',
        rejectLabel: 'Cancelar',
        accept: async () => {
            try {
                const { error } = await supabase.from('login_carousel_slides').delete().eq('id', slide.id);
                if (error) throw error;
                toast.add({ severity: 'success', summary: 'Removido', detail: `Slide removido.`, life: 2500 });
                await load();
                previewIdx.value = 0;
            } catch (e) {
                toast.add({ severity: 'error', summary: 'Erro', detail: e?.message, life: 3000 });
            }
        }
    });
}

async function moveSlide(slide, dir) {
    const sorted = [...slides.value].sort((a, b) => a.ordem - b.ordem);
    const idx = sorted.findIndex((s) => s.id === slide.id);
    const swapIdx = idx + dir;
    if (swapIdx < 0 || swapIdx >= sorted.length) return;

    const a = sorted[idx];
    const b = sorted[swapIdx];
    const tempOrdem = a.ordem;

    try {
        await supabase.from('login_carousel_slides').update({ ordem: b.ordem }).eq('id', a.id);
        await supabase.from('login_carousel_slides').update({ ordem: tempOrdem }).eq('id', b.id);
        await load();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message, life: 3000 });
    }
}

// ─── Dialog helpers ───────────────────────────────────────────────────────────
function openNew() {
    editingSlide.value = null;
    form.value = { title: '', body: '', icon: 'pi-calendar-clock', ordem: 0, ativo: true };
    dialogOpen.value = true;
}

function openEdit(slide) {
    editingSlide.value = slide;
    form.value = { title: slide.title, body: slide.body, icon: slide.icon || 'pi-star', ordem: slide.ordem, ativo: slide.ativo };
    dialogOpen.value = true;
}

onMounted(load);
</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-images" /></div>
            <div class="min-w-0 flex-1">
                <div class="cfg-subheader__title">Carrossel do Login</div>
                <div class="cfg-subheader__sub">Gerencie os slides exibidos na tela de login do sistema.</div>
            </div>
            <div class="flex items-center gap-2 shrink-0">
                <Button icon="pi pi-refresh" severity="secondary" outlined size="small" v-tooltip.bottom="'Recarregar'" :loading="loading" @click="load" />
                <Button icon="pi pi-plus" label="Novo slide" size="small" @click="openNew" />
            </div>
        </div>
        <div class="grid grid-cols-1 xl:grid-cols-[1fr_340px] gap-6 items-start">
            <!-- ── Tabela de slides ──────────────────────────────────────────────── -->
            <div class="bg-[var(--surface-card,#fff)] rounded-md border border-[var(--surface-border)] overflow-hidden">
                <!-- Loading skeleton -->
                <div v-if="loading" class="flex flex-col divide-y divide-[var(--surface-border)]">
                    <div v-for="i in 4" :key="i" class="flex items-center gap-4 px-5 py-4 animate-pulse">
                        <div class="w-10 h-10 rounded-md bg-[var(--surface-ground)] shrink-0" />
                        <div class="flex-1 space-y-2">
                            <div class="h-3.5 w-40 rounded bg-[var(--surface-ground)]" />
                            <div class="h-3 w-64 rounded bg-[var(--surface-ground)]" />
                        </div>
                    </div>
                </div>

                <!-- Lista vazia -->
                <div v-else-if="!slides.length" class="flex flex-col items-center justify-center py-16 gap-3 text-[var(--text-color-secondary)]">
                    <i class="pi pi-images text-4xl opacity-30" />
                    <span class="text-[1rem]">Nenhum slide cadastrado ainda.</span>
                    <Button label="Criar primeiro slide" size="small" @click="openNew" />
                </div>

                <!-- Rows -->
                <div v-else class="divide-y divide-[var(--surface-border)]">
                    <!-- Header -->
                    <div class="grid grid-cols-[auto_1fr_auto_auto] items-center gap-4 px-5 py-2.5 bg-[var(--surface-ground)] text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary)]">
                        <span class="w-10" />
                        <span>Slide</span>
                        <span class="text-center w-[60px]">Status</span>
                        <span class="w-[96px]" />
                    </div>

                    <div
                        v-for="(slide, i) in [...slides].sort((a, b) => a.ordem - b.ordem)"
                        :key="slide.id"
                        class="grid grid-cols-[auto_1fr_auto_auto] items-center gap-4 px-5 py-3.5 transition-colors duration-100 hover:bg-[var(--surface-ground,#f8fafc)] group"
                    >
                        <!-- Ícone + ordem -->
                        <div class="relative shrink-0">
                            <div class="w-10 h-10 rounded-md flex items-center justify-center text-lg" :class="slide.ativo ? 'bg-indigo-500/10 text-indigo-500' : 'bg-[var(--surface-ground)] text-[var(--text-color-secondary)]'">
                                <i :class="['pi', slide.icon || 'pi-star']" />
                            </div>
                            <span class="absolute -top-1 -right-1 w-4 h-4 rounded-full bg-[var(--surface-border)] text-[0.58rem] font-bold flex items-center justify-center text-[var(--text-color-secondary)]">
                                {{ slide.ordem + 1 }}
                            </span>
                        </div>

                        <!-- Conteúdo -->
                        <div class="min-w-0">
                            <div class="text-[1rem] font-semibold text-[var(--text-color)] truncate [&_*]:inline" :class="!slide.ativo && 'opacity-40 line-through'" v-html="slide.title" />
                            <div class="text-[1rem] text-[var(--text-color-secondary)] truncate mt-0.5 [&_*]:inline" :class="!slide.ativo && 'opacity-40'" v-html="slide.body" />
                        </div>

                        <!-- Toggle ativo -->
                        <div class="flex justify-center w-[60px]">
                            <ToggleSwitch :modelValue="slide.ativo" @update:modelValue="() => toggleAtivo(slide)" />
                        </div>

                        <!-- Ações -->
                        <div class="flex items-center gap-1 w-[96px] justify-end opacity-0 group-hover:opacity-100 transition-opacity duration-150">
                            <button
                                class="w-7 h-7 rounded-md flex items-center justify-center text-[var(--text-color-secondary)] hover:bg-[var(--surface-border)] hover:text-[var(--text-color)] transition-colors duration-100 disabled:opacity-30"
                                :disabled="i === 0"
                                title="Mover para cima"
                                @click="moveSlide(slide, -1)"
                            >
                                <i class="pi pi-chevron-up text-xs" />
                            </button>
                            <button
                                class="w-7 h-7 rounded-md flex items-center justify-center text-[var(--text-color-secondary)] hover:bg-[var(--surface-border)] hover:text-[var(--text-color)] transition-colors duration-100 disabled:opacity-30"
                                :disabled="i === slides.length - 1"
                                title="Mover para baixo"
                                @click="moveSlide(slide, 1)"
                            >
                                <i class="pi pi-chevron-down text-xs" />
                            </button>
                            <button class="w-7 h-7 rounded-md flex items-center justify-center text-[var(--text-color-secondary)] hover:bg-indigo-50 hover:text-indigo-600 transition-colors duration-100" title="Editar" @click="openEdit(slide)">
                                <i class="pi pi-pencil text-xs" />
                            </button>
                            <button class="w-7 h-7 rounded-md flex items-center justify-center text-[var(--text-color-secondary)] hover:bg-red-50 hover:text-red-500 transition-colors duration-100" title="Remover" @click="deleteSlide(slide)">
                                <i class="pi pi-trash text-xs" />
                            </button>
                        </div>
                    </div>
                </div>
            </div>

            <!-- ── Preview ──────────────────────────────────────────────────────── -->
            <div class="sticky top-6 flex flex-col gap-3">
                <div class="text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary)] flex items-center gap-1.5 px-1"><i class="pi pi-eye" /> Pré-visualização</div>

                <!-- Mock da tela de login — lado esquerdo -->
                <div class="relative overflow-hidden rounded-md aspect-[9/16] max-h-[480px] w-full select-none shadow-xl">
                    <div class="absolute inset-0 bg-gradient-to-br from-indigo-600 via-violet-600 to-purple-700" />

                    <!-- Grade decorativa -->
                    <div class="absolute inset-0 opacity-[0.08]" style="background-image: linear-gradient(to right, white 1px, transparent 1px), linear-gradient(to bottom, white 1px, transparent 1px); background-size: 32px 32px" />

                    <!-- Orbs -->
                    <div class="absolute -top-20 -left-20 h-64 w-64 rounded-full bg-white/10 blur-3xl pointer-events-none" />
                    <div class="absolute bottom-0 right-0 h-48 w-48 rounded-full bg-violet-300/20 blur-3xl pointer-events-none" />

                    <div class="relative z-10 flex flex-col h-full p-6">
                        <!-- Brand mock -->
                        <div class="flex items-center gap-2">
                            <div class="grid h-7 w-7 place-items-center rounded-lg bg-white/20 border border-white/20">
                                <i class="pi pi-heart-fill text-white text-[0.6rem]" />
                            </div>
                            <span class="text-white/90 font-bold text-xs tracking-tight">Agência PSI</span>
                        </div>

                        <!-- Slide content -->
                        <div class="flex-1 flex flex-col justify-center gap-4">
                            <Transition name="prev-fade" mode="out-in">
                                <div v-if="previewSlide" :key="previewSlide.id ?? previewIdx" class="space-y-4">
                                    <div class="grid h-11 w-11 place-items-center rounded-md bg-white/15 border border-white/20 shadow-lg">
                                        <i :class="['pi', previewSlide.icon || 'pi-star', 'text-white text-lg']" />
                                    </div>
                                    <div class="space-y-2">
                                        <div class="text-xl font-bold text-white leading-tight prose prose-invert prose-sm max-w-none" v-html="previewSlide.title" />
                                        <div class="text-[1rem] text-white/70 leading-relaxed prose prose-invert prose-sm max-w-none" v-html="previewSlide.body" />
                                    </div>
                                </div>
                                <div v-else class="flex flex-col items-center justify-center gap-2 text-white/30 text-xs">
                                    <i class="pi pi-ban text-2xl" />
                                    Nenhum slide ativo
                                </div>
                            </Transition>
                        </div>

                        <!-- Dots -->
                        <div class="flex items-center gap-1.5">
                            <button
                                v-for="(s, i) in slidesAtivos"
                                :key="s.id"
                                class="transition-all duration-300 rounded-full"
                                :class="i === previewIdx ? 'w-5 h-1.5 bg-white shadow' : 'w-1.5 h-1.5 bg-white/35 hover:bg-white/60'"
                                @click="previewIdx = i"
                            />
                            <span v-if="slidesAtivos.length" class="ml-2 text-[0.6rem] text-white/40 tabular-nums"> {{ previewIdx + 1 }}/{{ slidesAtivos.length }} </span>
                        </div>
                    </div>
                </div>

                <!-- Info -->
                <div class="rounded-lg border border-[var(--surface-border)] bg-[var(--surface-card)] px-4 py-3 text-xs text-[var(--text-color-secondary)] flex items-start gap-2">
                    <i class="pi pi-info-circle text-indigo-500 mt-px shrink-0" />
                    <span>Clique nos pontos para navegar entre os slides ativos. A ordem e visibilidade refletem o que o usuário verá no login.</span>
                </div>
            </div>
        </div>

        <!-- ── SQL Helper ───────────────────────────────────────────────────────── -->
        <div class="bg-[var(--surface-card)] rounded-md border border-[var(--surface-border)] px-5 py-4">
            <div class="flex items-center gap-2 mb-3">
                <i class="pi pi-database text-amber-500 text-[1rem]" />
                <span class="text-xs font-bold text-[var(--text-color)] uppercase tracking-widest">SQL de referência</span>
                <span class="ml-auto text-xs text-[var(--text-color-secondary)]">Execute no Supabase caso a tabela não exista</span>
            </div>
            <pre class="text-[0.7rem] bg-[var(--surface-ground)] rounded-lg p-3.5 overflow-x-auto text-[var(--text-color-secondary)] leading-relaxed whitespace-pre-wrap"><code>create table if not exists public.login_carousel_slides (
  id      uuid primary key default gen_random_uuid(),
  title   text not null,
  body    text not null,
  icon    text not null default 'pi-star',
  ordem   integer not null default 0,
  ativo   boolean not null default true,
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

-- RLS: apenas saas_admin pode gerenciar
alter table public.login_carousel_slides enable row level security;

create policy "saas_admin_full" on public.login_carousel_slides
  for all using (
    exists (
      select 1 from public.profiles
      where id = auth.uid() and role = 'saas_admin'
    )
  );

-- Leitura pública (login não tem usuário autenticado)
create policy "public_read" on public.login_carousel_slides
  for select using (ativo = true);</code></pre>
        </div>
    </div>

    <!-- /px-3 content wrapper -->

    <!-- ── Dialog: Criar / Editar slide ───────────────────────────────────────── -->
    <Dialog v-model:visible="dialogOpen" modal :header="editingSlide ? 'Editar slide' : 'Novo slide'" :draggable="false" :style="{ width: '46rem', maxWidth: '96vw' }">
        <div class="flex flex-col gap-4 pt-1">
            <!-- Título -->
            <div class="flex flex-col gap-1.5">
                <label class="text-[1rem] font-semibold text-[var(--text-color)]">Título <span class="text-red-500">*</span></label>
                <Editor v-model="form.title" :pt="{ toolbar: { style: 'display:none' } }" style="height: 72px" editorStyle="font-size: 1rem; font-weight: 600;" placeholder="Ex: Gestão clínica simplificada">
                    <template #toolbar>
                        <span class="ql-formats">
                            <button class="ql-bold" />
                            <button class="ql-italic" />
                            <button class="ql-underline" />
                        </span>
                    </template>
                </Editor>
            </div>

            <!-- Conteúdo -->
            <div class="flex flex-col gap-1.5">
                <label class="text-[1rem] font-semibold text-[var(--text-color)]">Conteúdo <span class="text-red-500">*</span></label>
                <Editor v-model="form.body" style="height: 160px" editorStyle="font-size: 1rem;">
                    <template #toolbar>
                        <span class="ql-formats">
                            <button class="ql-bold" />
                            <button class="ql-italic" />
                            <button class="ql-underline" />
                        </span>
                        <span class="ql-formats">
                            <button class="ql-list" value="ordered" />
                            <button class="ql-list" value="bullet" />
                        </span>
                        <span class="ql-formats">
                            <button class="ql-link" />
                            <button class="ql-clean" />
                        </span>
                    </template>
                </Editor>
            </div>

            <!-- Ícone -->
            <div class="flex flex-col gap-1.5">
                <label class="text-[1rem] font-semibold text-[var(--text-color)]">Ícone</label>
                <div class="grid grid-cols-4 sm:grid-cols-8 gap-1.5">
                    <button
                        v-for="ic in ICONS"
                        :key="ic.value"
                        type="button"
                        class="flex flex-col items-center justify-center gap-1 py-2 rounded-lg border text-xs transition-all duration-100"
                        :class="
                            form.icon === ic.value
                                ? 'border-indigo-500 bg-indigo-50 text-indigo-600 shadow-sm'
                                : 'border-[var(--surface-border)] bg-[var(--surface-ground)] text-[var(--text-color-secondary)] hover:border-indigo-300 hover:text-indigo-500'
                        "
                        :title="ic.label"
                        @click="form.icon = ic.value"
                    >
                        <i :class="['pi', ic.value, 'text-base']" />
                        <span class="text-[0.6rem] leading-none">{{ ic.label }}</span>
                    </button>
                </div>
            </div>

            <!-- Ativo -->
            <div class="flex items-center gap-3">
                <ToggleSwitch v-model="form.ativo" inputId="slide-ativo" />
                <label for="slide-ativo" class="text-[1rem] text-[var(--text-color)] cursor-pointer select-none"> Slide ativo (visível no carrossel) </label>
            </div>

            <!-- Mini preview -->
            <div class="relative overflow-hidden rounded-md p-5 flex items-center gap-4" style="background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%)">
                <div class="grid h-12 w-12 shrink-0 place-items-center rounded-md bg-white/15 border border-white/20 shadow">
                    <i :class="['pi', form.icon || 'pi-star', 'text-white text-xl']" />
                </div>
                <div class="min-w-0 overflow-hidden">
                    <div class="text-[1rem] font-bold text-white line-clamp-2 prose prose-invert prose-sm max-w-none" v-html="stripHtml(form.title) ? form.title : 'Título do slide'" />
                    <div class="text-[1rem] text-white/70 mt-0.5 line-clamp-3 prose prose-invert prose-sm max-w-none" v-html="stripHtml(form.body) ? form.body : 'Conteúdo descritivo...'" />
                </div>
            </div>

            <!-- Ações -->
            <div class="flex justify-end gap-2 pt-1">
                <Button label="Cancelar" severity="secondary" outlined :disabled="saving" @click="dialogOpen = false" />
                <Button :label="editingSlide ? 'Salvar alterações' : 'Criar slide'" icon="pi pi-check" :loading="saving" @click="saveSlide" />
            </div>
        </div>
    </Dialog>
</template>

<style scoped>
.prev-fade-enter-active,
.prev-fade-leave-active {
    transition:
        opacity 0.3s ease,
        transform 0.3s ease;
}
.prev-fade-enter-from {
    opacity: 0;
    transform: translateY(12px);
}
.prev-fade-leave-to {
    opacity: 0;
    transform: translateY(-8px);
}
</style>
