<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/layout/configuracoes/ConfiguracoesAgendaPage.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<script setup>
import { supabase } from '@/lib/supabase/client';
import { tenantDb } from '@/lib/supabase/tenantClient';
import { useTenantStore } from '@/stores/tenantStore';
import { computed, nextTick, onMounted, ref, watch } from 'vue';

import DatePicker from 'primevue/datepicker';
import { useToast } from 'primevue/usetoast';

import PausasChipsEditor from '@/components/agenda/PausasChipsEditor.vue';

import ptBrLocale from '@fullcalendar/core/locales/pt-br';
import timeGridPlugin from '@fullcalendar/timegrid';
import FullCalendar from '@fullcalendar/vue3';

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

// ── Estado global ──────────────────────────────────────────────
const loading = ref(true);
const hydrating = ref(true);
const ownerId = ref(null);

// Card aberto: 'jornada' | 'ritmo' | 'online' | null
const expandedCard = ref(null);
// Qual card está salvando
const savingCard = ref(null);

// ── cfg (agenda_configuracoes) ──────────────────────────────────
const cfg = ref({
    owner_id: null,
    agenda_view_mode: 'work_hours',
    agenda_custom_start: null,
    agenda_custom_end: null,
    session_duration_min: 40,
    session_break_min: 10,
    pausas_semanais: [],
    online_ativo: false,
    setup_clinica_concluido: false,
    setup_clinica_concluido_em: null,
    jornada_igual_todos: true,
    timezone: 'America/Sao_Paulo',
    is_conveniado: false
});

const timezones = [
    { label: 'Brasília (BRT)', value: 'America/Sao_Paulo' },
    { label: 'Manaus (AMT)', value: 'America/Manaus' },
    { label: 'Fortaleza (BRT)', value: 'America/Fortaleza' },
    { label: 'Belém (BRT)', value: 'America/Belem' },
    { label: 'Rio Branco (ACT)', value: 'America/Rio_Branco' },
    { label: 'Noronha (FNT)', value: 'America/Noronha' },
    { label: 'Lisboa (WET)', value: 'Europe/Lisbon' }
];

// ── Jornada ────────────────────────────────────────────────────
const regras = ref([]);
const workDays = ref({ 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 0: false });
const jornadaStart = ref('08:00');
const jornadaEnd = ref('18:00');
const jornadaIgualTodos = ref(true);

const jornadaPorDia = ref({
    1: { inicio: '08:00', fim: '18:00' },
    2: { inicio: '08:00', fim: '18:00' },
    3: { inicio: '08:00', fim: '18:00' },
    4: { inicio: '08:00', fim: '18:00' },
    5: { inicio: '08:00', fim: '18:00' },
    6: { inicio: '08:00', fim: '18:00' },
    0: { inicio: '08:00', fim: '18:00' }
});

// Snapshot dos horários por dia do modo "diferente" — preservado ao alternar modos
const jornadaPorDiaSnapshot = ref(null);

// ── Pausas ──────────────────────────────────────────────────────
const pausasGlobais = ref([]);
const pausasPorDia = ref({ 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 0: [] });

// ── Online ──────────────────────────────────────────────────────
const onlineSlotsByDay = ref({ 1: new Set(), 2: new Set(), 3: new Set(), 4: new Set(), 5: new Set(), 6: new Set(), 0: new Set() });

function resetOnlineSlots() {
    onlineSlotsByDay.value = { 1: new Set(), 2: new Set(), 3: new Set(), 4: new Set(), 5: new Set(), 6: new Set(), 0: new Set() };
}

// ── Ritmo preset ────────────────────────────────────────────────
const showAdvancedRitmo = ref(false);

// ── Preview day ─────────────────────────────────────────────────
const previewDay = ref(null);

// ══ CONSTANTES / HELPERS ══════════════════════════════════════
const diasSemana = [
    { label: 'Segunda', short: 'Seg', value: 1 },
    { label: 'Terça', short: 'Ter', value: 2 },
    { label: 'Quarta', short: 'Qua', value: 3 },
    { label: 'Quinta', short: 'Qui', value: 4 },
    { label: 'Sexta', short: 'Sex', value: 5 },
    { label: 'Sábado', short: 'Sáb', value: 6 },
    { label: 'Domingo', short: 'Dom', value: 0 }
];

const selectedDays = computed(() => diasSemana.filter((d) => !!workDays.value[d.value]));
const selectedWeekdays = computed(() => diasSemana.filter((d) => d.value >= 1 && d.value <= 5 && !!workDays.value[d.value]));

function hhmmToMin(hhmm) {
    const [h, m] = String(hhmm).split(':').map(Number);
    return h * 60 + m;
}
function minToHHMM(min) {
    const h = Math.floor(min / 60) % 24;
    const m = min % 60;
    return String(h).padStart(2, '0') + ':' + String(m).padStart(2, '0');
}
function isValidHHMM(v) {
    if (!v) return false;
    return /^\d{2}:\d{2}$/.test(String(v).trim());
}
function normalizeTime(v) {
    if (v == null || v === '') return null;
    const s = String(v).trim();
    if (/^\d{2}:\d{2}$/.test(s)) return s + ':00';
    if (/^\d{2}:\d{2}:\d{2}$/.test(s)) return s;
    return s;
}
function newId() {
    return Math.random().toString(16).slice(2) + Date.now().toString(16);
}
function overlapsInDay(pausas) {
    const list = (pausas || []).map((p) => ({ ...p, s: hhmmToMin(p.inicio), e: hhmmToMin(p.fim) })).sort((a, b) => a.s - b.s);
    for (let i = 1; i < list.length; i++) if (list[i].s < list[i - 1].e) return true;
    return false;
}
function dateToHHMM(date) {
    if (!date) return null;
    const d = date instanceof Date ? date : new Date(date);
    if (Number.isNaN(d.getTime())) return null;
    return String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
}
function hhmmToDate(hhmm) {
    if (!isValidHHMM(hhmm)) return null;
    const [h, m] = String(hhmm).split(':').map(Number);
    const d = new Date();
    d.setHours(h, m, 0, 0);
    return d;
}
function dateForDayOfWeek(dayValue) {
    const now = new Date();
    const delta = (dayValue - now.getDay() + 7) % 7;
    const d = new Date(now);
    d.setHours(0, 0, 0, 0);
    d.setDate(d.getDate() + delta);
    return d;
}
function floorTo30(hhmm) {
    const [h, m] = String(hhmm || '00:00')
        .slice(0, 5)
        .split(':')
        .map(Number);
    return String(h).padStart(2, '0') + ':' + (m < 30 ? '00' : '30');
}
function ceilTo30(hhmm) {
    const [h, m] = String(hhmm || '00:00')
        .slice(0, 5)
        .split(':')
        .map(Number);
    if (m === 0 || m === 30) return String(h).padStart(2, '0') + ':' + String(m).padStart(2, '0');
    if (m < 30) return String(h).padStart(2, '0') + ':30';
    return String(h + 1).padStart(2, '0') + ':00';
}

function toLocalIsoAt(dateBase, hhmm) {
    const [h, m] = String(hhmm).split(':').map(Number);
    const d = new Date(dateBase);
    d.setHours(h, m, 0, 0);
    const p = (v) => String(v).padStart(2, '0');
    return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}:00`;
}

// ══ RESUMOS DOS CARDS ═════════════════════════════════════════
const resumoJornada = computed(() => {
    const days = selectedDays.value;
    if (!days.length) return 'Nenhum dia configurado';
    const labels = days.map((d) => d.short).join('·');
    if (jornadaIgualTodos.value !== false) {
        return `${labels}  ·  ${jornadaStart.value}–${jornadaEnd.value}`;
    }
    return `${labels}  ·  horários variados`;
});

const jornadaOk = computed(() => selectedDays.value.length > 0 && isValidHHMM(jornadaStart.value) && isValidHHMM(jornadaEnd.value) && jornadaEnd.value > jornadaStart.value);

const resumoRitmo = computed(() => {
    const d = cfg.value.session_duration_min || 50;
    const i = cfg.value.session_break_min || 0;
    return `${d} min sessão · ${i > 0 ? `${i} min intervalo` : 'sem intervalo'}`;
});

const resumoOnline = computed(() => {
    if (!cfg.value.online_ativo) return 'Desativado';
    let total = 0;
    let dias = 0;
    for (const k of Object.keys(onlineSlotsByDay.value)) {
        const size = onlineSlotsByDay.value[k]?.size || 0;
        total += size;
        if (size > 0) dias++;
    }
    return `Ativo · ${total} slot${total !== 1 ? 's' : ''} configurado${total !== 1 ? 's' : ''} em ${dias} dia${dias !== 1 ? 's' : ''}`;
});

// Dias que têm slots no banco mas não estão mais na jornada (órfãos)
const orphanSlotDays = computed(() => {
    const active = new Set(selectedDays.value.map((d) => d.value));
    return diasSemana.filter((d) => !active.has(d.value) && (onlineSlotsByDay.value[d.value]?.size || 0) > 0).map((d) => d.short);
});

// ══ SYNC / HYDRATE ════════════════════════════════════════════
watch(
    [selectedDays, jornadaStart, jornadaEnd],
    () => {
        if (!isValidHHMM(jornadaStart.value) || !isValidHHMM(jornadaEnd.value)) return;
        if (jornadaIgualTodos.value !== false) {
            // Sync apenas Seg–Sex; Sáb e Dom têm horário próprio
            selectedDays.value
                .filter((d) => d.value >= 1 && d.value <= 5)
                .forEach((d) => {
                    jornadaPorDia.value[d.value] = { inicio: jornadaStart.value, fim: jornadaEnd.value };
                });
        }
    },
    { immediate: true }
);

// retorna as pausas ao vivo para um dia (sem depender de cfg.value.pausas_semanais)
function getPausasForDay(dayValue) {
    if (jornadaIgualTodos.value !== false) return pausasGlobais.value;
    return pausasPorDia.value[dayValue] || [];
}

// ── Toggle igual/diferente ─────────────────────────────────────
function switchToIgual() {
    // Salva o estado atual de "diferente" no snapshot antes de sair
    jornadaPorDiaSnapshot.value = {};
    selectedDays.value.forEach((d) => {
        if (jornadaPorDia.value[d.value]) jornadaPorDiaSnapshot.value[d.value] = { ...jornadaPorDia.value[d.value] };
    });

    // jornadaStart/jornadaEnd ficam intocados — eram os valores do modo "igual"
    if (isValidHHMM(jornadaStart.value) && isValidHHMM(jornadaEnd.value)) {
        // Sync apenas Seg–Sex; Sáb e Dom mantêm horário próprio
        selectedDays.value
            .filter((d) => d.value >= 1 && d.value <= 5)
            .forEach((d) => {
                jornadaPorDia.value[d.value] = { inicio: jornadaStart.value, fim: jornadaEnd.value };
            });
        // Inicializa Sáb/Dom com horário global se ainda não tiver valor
        [6, 0].forEach((v) => {
            if (workDays.value[v] && !jornadaPorDia.value[v]?.inicio) jornadaPorDia.value[v] = { inicio: jornadaStart.value, fim: jornadaEnd.value };
        });
    }
    // Copia pausas globais para todos os dias e usa apenas pausasGlobais
    selectedDays.value.forEach((d) => {
        pausasPorDia.value[d.value] = [];
    });
    jornadaIgualTodos.value = true;
}

function switchToDiferente() {
    selectedDays.value.forEach((d) => {
        const isWeekend = d.value === 6 || d.value === 0;
        const snap = jornadaPorDiaSnapshot.value?.[d.value];
        if (snap && isValidHHMM(snap.inicio) && isValidHHMM(snap.fim)) {
            // Restaura do snapshot (vale para todos os dias)
            jornadaPorDia.value[d.value] = { ...snap };
        } else if (!isWeekend) {
            // Dia de semana sem snapshot: inicia com 08:00–18:00
            jornadaPorDia.value[d.value] = { inicio: '08:00', fim: '18:00' };
        }
        // Sáb/Dom sem snapshot: mantém o valor atual (já configurado no modo "igual")
    });
    selectedDays.value.forEach((d) => {
        pausasPorDia.value[d.value] = pausasGlobais.value.map((p) => ({ ...p, id: newId() }));
    });
    jornadaIgualTodos.value = false;
}

function hydratePausasFromCfg() {
    const byDay = { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 0: [] };
    for (const p of cfg.value.pausas_semanais || []) {
        const d = p.dia_semana;
        if (byDay[d]) byDay[d].push({ ...p, id: p.id || newId() });
    }
    pausasPorDia.value = byDay;
    const first = selectedDays.value[0]?.value;
    if (jornadaIgualTodos.value !== false) {
        pausasGlobais.value = first != null ? (byDay[first] || []).map((p) => ({ ...p })) : [];
    }
}

function hydrateWizardFromRegras(dbRegras) {
    const map = { 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 0: false };
    const byDay = { ...jornadaPorDia.value };
    const actives = (dbRegras || []).filter((r) => r.ativo);

    if (!actives.length) {
        workDays.value = map;
        jornadaIgualTodos.value = true;
        regras.value = [];
        return;
    }

    actives.forEach((r) => {
        map[r.dia_semana] = true;
        byDay[r.dia_semana] = {
            inicio: String(r.hora_inicio || '').slice(0, 5),
            fim: String(r.hora_fim || '').slice(0, 5)
        };
    });

    workDays.value = map;
    jornadaPorDia.value = byDay;

    // Usa apenas dias de semana (1–5) para determinar allSame e o horário padrão.
    // Sáb (6) e Dom (0) têm horários próprios e não devem afetar o modo "igual para todos".
    const weekdayActives = actives.filter((r) => r.dia_semana >= 1 && r.dia_semana <= 5);
    const ref = weekdayActives.length ? weekdayActives[0] : actives[0];

    const allSame =
        weekdayActives.length >= 2 ? weekdayActives.every((r) => String(r.hora_inicio || '').slice(0, 5) === String(ref.hora_inicio || '').slice(0, 5) && String(r.hora_fim || '').slice(0, 5) === String(ref.hora_fim || '').slice(0, 5)) : true;

    jornadaIgualTodos.value = allSame;
    jornadaStart.value = String(ref.hora_inicio || '').slice(0, 5) || '08:00';
    jornadaEnd.value = String(ref.hora_fim || '').slice(0, 5) || '18:00';

    // Se carregou em modo "diferente", popula o snapshot para preservar ao alternar modos
    if (!allSame) {
        jornadaPorDiaSnapshot.value = {};
        Object.keys(byDay).forEach((k) => {
            jornadaPorDiaSnapshot.value[k] = { ...byDay[k] };
        });
    }

    regras.value = actives.map((r) => ({
        ...r,
        hora_inicio: String(r.hora_inicio || '').slice(0, 5),
        hora_fim: String(r.hora_fim || '').slice(0, 5)
    }));
}

// ══ AUTH / TENANT ═════════════════════════════════════════════
async function getOwnerId() {
    const { data, error } = await supabase.auth.getUser();
    if (error) throw error;
    const uid = data?.user?.id;
    if (!uid) throw new Error('Sessão inválida.');
    return uid;
}

async function getActiveTenantId(uid) {
    const fromStore = tenantStore.activeTenantId || tenantStore.tenantId || tenantStore.currentTenantId || tenantStore.tenant?.id || null;
    if (fromStore) return fromStore;

    const { data } = await supabase.from('tenant_members').select('tenant_id').eq('user_id', uid).eq('status', 'active').limit(1).maybeSingle();
    return data?.tenant_id || null;
}

async function seedConfigIfMissing(uid) {
    const { data: existing } = await tenantDb().from('agenda_configuracoes').select('owner_id').eq('owner_id', uid).maybeSingle();
    if (existing) return; // já existe, não toca

    const tenantId = await getActiveTenantId(uid);
    const { error } = await tenantDb().from('agenda_configuracoes').insert({ owner_id: uid, session_duration_min: 40, session_break_min: 10 });
    if (error) throw error;
}

// ══ LOAD ══════════════════════════════════════════════════════
async function loadConfig() {
    const uid = await getOwnerId();
    ownerId.value = uid;
    cfg.value.owner_id = uid;

    await seedConfigIfMissing(uid);

    const { data, error } = await tenantDb().from('agenda_configuracoes').select('*').eq('owner_id', uid).order('created_at', { ascending: false }).limit(1).maybeSingle();
    if (error) throw error;
    if (data) {
        cfg.value = { ...cfg.value, ...data };
        if (!Array.isArray(cfg.value.pausas_semanais)) cfg.value.pausas_semanais = [];
    }
}

async function loadRegras() {
    const uid = ownerId.value || (await getOwnerId());
    ownerId.value = uid;

    const { data, error } = await tenantDb().from('agenda_regras_semanais').select('*').eq('owner_id', uid).order('dia_semana').order('hora_inicio');
    if (error) throw error;

    const rows = (data || []).map((r) => ({
        ...r,
        hora_inicio: String(r.hora_inicio || '').slice(0, 5),
        hora_fim: String(r.hora_fim || '').slice(0, 5),
        ativo: !!r.ativo
    }));

    hydrateWizardFromRegras(rows);
}

async function loadOnlineSlots() {
    const uid = ownerId.value || (await getOwnerId());
    ownerId.value = uid;
    resetOnlineSlots();

    const { data, error } = await tenantDb().from('agenda_online_slots').select('weekday,time,enabled').eq('owner_id', uid);
    if (error) {
        console.warn('[CFG] loadOnlineSlots:', error);
        return;
    }

    for (const row of data || []) {
        if (!row?.enabled) continue;
        const d = Number(row.weekday);
        const t = String(row.time || '').slice(0, 5);
        if ([0, 1, 2, 3, 4, 5, 6].includes(d) && isValidHHMM(t)) onlineSlotsByDay.value[d].add(t);
    }
}

async function boot() {
    hydrating.value = true;
    loading.value = true;
    try {
        await loadConfig();
        await loadRegras();
        // sobrescreve a inferência de allSame com a preferência salva no BD
        if (cfg.value.jornada_igual_todos != null) {
            jornadaIgualTodos.value = cfg.value.jornada_igual_todos;
        }
        hydratePausasFromCfg();
        await loadOnlineSlots();
        // abre o primeiro card se setup não foi concluído
        if (!cfg.value.setup_clinica_concluido) expandedCard.value = 'jornada';
        // define preview para primeiro dia ativo
        const first = selectedDays.value[0];
        previewDay.value = first?.value ?? 1;
    } catch (e) {
        console.error(e);
        toast.add({ severity: 'error', summary: 'Erro ao carregar', detail: e?.message, life: 4000 });
    } finally {
        loading.value = false;
        hydrating.value = false;
    }
}

onMounted(boot);

// ══ SAVE POR CARD ════════════════════════════════════════════
async function saveJornada() {
    if (!jornadaOk.value) {
        toast.add({ severity: 'warn', summary: 'Jornada', detail: 'Selecione ao menos um dia e informe horários válidos.', life: 3500 });
        return;
    }

    savingCard.value = 'jornada';
    try {
        const uid = ownerId.value || (await getOwnerId());
        ownerId.value = uid;
        const tenantId = await getActiveTenantId(uid);

        // 1. salvar pausas + cfg — lê diretamente dos refs para evitar race condition
        const pausasToSave = [];
        if (jornadaIgualTodos.value !== false) {
            for (const d of selectedDays.value) for (const p of pausasGlobais.value) pausasToSave.push({ ...p, dia_semana: d.value });
        } else {
            for (const d of selectedDays.value) for (const p of pausasPorDia.value[d.value] || []) pausasToSave.push({ ...p, dia_semana: d.value });
        }
        cfg.value.pausas_semanais = pausasToSave;

        const igualTodos = jornadaIgualTodos.value !== false;
        const { data: cfgSaved, error: cfgErr } = await tenantDb().from('agenda_configuracoes')
            .upsert(
                {
                    owner_id: uid,
                    pausas_semanais: pausasToSave,
                    jornada_igual_todos: igualTodos,
                    timezone: cfg.value.timezone || 'America/Sao_Paulo',
                    setup_clinica_concluido: true,
                    setup_clinica_concluido_em: cfg.value.setup_clinica_concluido_em || new Date().toISOString()
                },
                { onConflict: 'owner_id' }
            )
            .select('pausas_semanais, jornada_igual_todos');
        if (cfgErr) throw cfgErr;

        // 2. regras semanais
        const rows = selectedDays.value.map((d) => {
            const isWeekend = d.value === 6 || d.value === 0;
            const t = jornadaIgualTodos.value === false || isWeekend ? jornadaPorDia.value[d.value] || { inicio: jornadaStart.value, fim: jornadaEnd.value } : { inicio: jornadaStart.value, fim: jornadaEnd.value };
            return { owner_id: uid, dia_semana: d.value, hora_inicio: normalizeTime(t.inicio), hora_fim: normalizeTime(t.fim), modalidade: 'ambos', ativo: true };
        });

        const { error: delErr } = await tenantDb().from('agenda_regras_semanais').delete().eq('owner_id', uid);
        if (delErr) throw delErr;
        if (rows.length) {
            const { error: insErr } = await tenantDb().from('agenda_regras_semanais').insert(rows);
            if (insErr) throw insErr;
        }

        // Limpar slots online de dias removidos da jornada
        const activeDays = new Set(selectedDays.value.map((d) => d.value));
        const orphanDays = [0, 1, 2, 3, 4, 5, 6].filter((d) => !activeDays.has(d));
        if (orphanDays.length) {
            const { error: orphanErr } = await tenantDb().from('agenda_online_slots').delete().eq('owner_id', uid).in('weekday', orphanDays);
            if (orphanErr) console.warn('[CFG] limpeza órfãos:', orphanErr);
            else for (const d of orphanDays) _setDay(d, new Set());
        }

        cfg.value.setup_clinica_concluido = true;
        cfg.value.jornada_igual_todos = igualTodos;
        toast.add({ severity: 'success', summary: 'Jornada salva', detail: 'Horários de trabalho atualizados.', life: 3500 });
        // Notifica consumidores (ex: MelissaLayout/timeline) pra refetch
        // do agenda_regras_semanais sem precisar reload da página.
        window.dispatchEvent(new CustomEvent('agenda:settings-saved', { detail: { source: 'jornada' } }));
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao salvar jornada.', life: 3500 });
    } finally {
        savingCard.value = null;
    }
}

async function saveRitmo() {
    const dur = Number(cfg.value.session_duration_min || 0);
    const gap = Number(cfg.value.session_break_min || 0);

    if (dur < 10 || dur > 240) {
        toast.add({ severity: 'warn', summary: 'Ritmo', detail: 'Duração deve ser entre 10 e 240 min.', life: 3500 });
        return;
    }
    if (gap < 0 || gap > 60) {
        toast.add({ severity: 'warn', summary: 'Ritmo', detail: 'Intervalo deve ser entre 0 e 60 min.', life: 3500 });
        return;
    }

    savingCard.value = 'ritmo';
    try {
        const uid = ownerId.value || (await getOwnerId());
        ownerId.value = uid;

        const { error } = await tenantDb().from('agenda_configuracoes').upsert(
            {
                owner_id: uid,
                session_duration_min: dur,
                session_break_min: gap
            },
            { onConflict: 'owner_id' }
        );
        if (error) throw error;

        toast.add({ severity: 'success', summary: 'Ritmo salvo', detail: 'Configurações de sessão atualizadas.', life: 1800 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao salvar ritmo.', life: 3500 });
    } finally {
        savingCard.value = null;
    }
}

async function saveOnline() {
    savingCard.value = 'online';
    try {
        const uid = ownerId.value || (await getOwnerId());
        ownerId.value = uid;
        const tenantId = await getActiveTenantId(uid);

        // salvar flag online_ativo
        const { error: cfgErr } = await tenantDb().from('agenda_configuracoes').upsert({ owner_id: uid, online_ativo: cfg.value.online_ativo }, { onConflict: 'owner_id' });
        if (cfgErr) throw cfgErr;

        // salvar slots
        const { error: delErr } = await tenantDb().from('agenda_online_slots').delete().eq('owner_id', uid);
        if (delErr) throw delErr;

        if (cfg.value.online_ativo) {
            const rows = [];
            for (const d of selectedDays.value) {
                for (const hhmm of onlineSlotsByDay.value[d.value] || new Set()) {
                    if (isValidHHMM(hhmm)) rows.push({ owner_id: uid, weekday: Number(d.value), time: normalizeTime(hhmm), enabled: true });
                }
            }
            if (rows.length) {
                const { error: insErr } = await tenantDb().from('agenda_online_slots').insert(rows);
                if (insErr) throw insErr;
            }
        }

        toast.add({ severity: 'success', summary: 'Online salvo', detail: 'Configurações de agendamento online atualizadas.', life: 1800 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao salvar.', life: 3500 });
    } finally {
        savingCard.value = null;
    }
}

// ══ LIVE REGRAS (reflete estado da UI sem precisar salvar) ════
const liveRegras = computed(() =>
    selectedDays.value.map((d) => {
        const t = jornadaPorDia.value[d.value] || { inicio: jornadaStart.value, fim: jornadaEnd.value };
        return { dia_semana: d.value, hora_inicio: t.inicio, hora_fim: t.fim, ativo: true };
    })
);

// ══ SLOTS ONLINE helpers ══════════════════════════════════════
function generateSlotsForDay(dayValue) {
    const windows = liveRegras.value
        .filter((r) => r.ativo && r.dia_semana === dayValue)
        .map((r) => ({ start: String(r.hora_inicio || '').slice(0, 5), end: String(r.hora_fim || '').slice(0, 5) }))
        .sort((a, b) => a.start.localeCompare(b.start));
    if (!windows.length) return [];

    const breaks = getPausasForDay(dayValue).map((p) => ({ start: String(p.inicio || '').slice(0, 5), end: String(p.fim || '').slice(0, 5) }));

    const duration = Number(cfg.value.session_duration_min || 50);
    const gap = Number(cfg.value.session_break_min || 10);
    const cycle = Math.max(1, duration + gap);
    const out = [];

    for (const w of windows) {
        const wStart = hhmmToMin(w.start);
        const wEnd = hhmmToMin(w.end);
        let t = wStart;

        while (t < wEnd) {
            const aEnd = t + duration;
            if (aEnd > wEnd) break;
            const conflict = breaks.find((b) => {
                const bS = hhmmToMin(b.start),
                    bE = hhmmToMin(b.end);
                return !(aEnd <= bS || t >= bE);
            });
            if (conflict) {
                t = hhmmToMin(conflict.end);
                continue;
            }
            out.push({ hhmm: minToHHMM(t), endHHMM: minToHHMM(aEnd) });
            t += cycle;
        }
    }

    const seen = new Set();
    return out
        .filter((s) => {
            if (seen.has(s.hhmm)) return false;
            seen.add(s.hhmm);
            return true;
        })
        .sort((a, b) => a.hhmm.localeCompare(b.hhmm));
}

const slotsByDay = computed(() => {
    const out = {};
    for (const d of selectedDays.value) out[d.value] = generateSlotsForDay(d.value);
    return out;
});

function isSlotEnabled(dayValue, hhmm) {
    return !!onlineSlotsByDay.value?.[dayValue]?.has?.(hhmm);
}

// ⚠️ Sempre espalha o objeto pai para Vue detectar a mudança (Sets não são reativos internamente)
function _setDay(dayValue, newSet) {
    onlineSlotsByDay.value = { ...onlineSlotsByDay.value, [dayValue]: newSet };
}
function toggleSlot(dayValue, hhmm) {
    const s = new Set(onlineSlotsByDay.value?.[dayValue] || []);
    if (s.has(hhmm)) s.delete(hhmm);
    else s.add(hhmm);
    _setDay(dayValue, s);
}
function enableAllDay(dayValue) {
    const set = new Set();
    for (const s of slotsByDay.value?.[dayValue] || []) set.add(s.hhmm);
    _setDay(dayValue, set);
}
function clearDay(dayValue) {
    _setDay(dayValue, new Set());
}

// Períodos: seleciona slots do dia que caem dentro do intervalo de horário
const periodos = [
    { label: 'Manhã', icon: 'pi-sun', from: '05:00', to: '12:00' },
    { label: 'Tarde', icon: 'pi-cloud', from: '12:00', to: '18:00' },
    { label: 'Noite', icon: 'pi-moon', from: '18:00', to: '24:00' }
];

function isPeriodoAtivo(dayValue, periodo) {
    const slots = (slotsByDay.value?.[dayValue] || []).filter((s) => s.hhmm >= periodo.from && s.hhmm < periodo.to);
    if (!slots.length) return false;
    return slots.every((s) => isSlotEnabled(dayValue, s.hhmm));
}

function togglePeriodo(dayValue, periodo) {
    const slots = (slotsByDay.value?.[dayValue] || []).filter((s) => s.hhmm >= periodo.from && s.hhmm < periodo.to);
    if (!slots.length) return;
    const s = new Set(onlineSlotsByDay.value?.[dayValue] || []);
    const allOn = slots.every((sl) => s.has(sl.hhmm));
    if (allOn) {
        for (const sl of slots) s.delete(sl.hhmm);
    } else {
        for (const sl of slots) s.add(sl.hhmm);
    }
    _setDay(dayValue, s);
}

function hasSlotsInPeriodo(dayValue, periodo) {
    return (slotsByDay.value?.[dayValue] || []).some((s) => s.hhmm >= periodo.from && s.hhmm < periodo.to);
}

// ══ PREVIEW (FullCalendar) ════════════════════════════════════
const fcRef = ref(null);

const previewFcEvents = computed(() => {
    const day = previewDay.value;
    if (day == null) return [];
    const base = dateForDayOfWeek(day);
    const events = [];

    // janelas de trabalho (background verde)
    for (const r of liveRegras.value.filter((r) => r.ativo && r.dia_semana === day)) {
        events.push({
            id: `work_${r.dia_semana}`,
            start: toLocalIsoAt(base, r.hora_inicio),
            end: toLocalIsoAt(base, r.hora_fim),
            display: 'background',
            color: 'var(--green-100)'
        });
    }

    // pausas (background vermelho)
    for (const p of getPausasForDay(day)) {
        events.push({
            id: `pause_${p.id || newId()}`,
            title: p.label || 'Pausa',
            start: toLocalIsoAt(base, p.inicio),
            end: toLocalIsoAt(base, p.fim),
            display: 'background',
            color: 'var(--red-200)'
        });
    }

    // slots gerados (visualização)
    for (const s of generateSlotsForDay(day)) {
        const isOnline = isSlotEnabled(day, s.hhmm);
        events.push({
            id: `slot_${s.hhmm}`,
            title: isOnline ? 'Sessão, também disponível online 🌐' : 'Sessão',
            start: toLocalIsoAt(base, s.hhmm),
            end: toLocalIsoAt(base, s.endHHMM),
            backgroundColor: 'var(--primary-color)',
            borderColor: 'transparent',
            textColor: '#fff'
        });
    }

    return events;
});

const previewBounds = computed(() => {
    const day = previewDay.value;
    const active = liveRegras.value.filter((r) => r.ativo && (day == null || r.dia_semana === day));
    if (!active.length) return { start: '06:00', end: '22:00' };
    const start = active.reduce((acc, r) => (r.hora_inicio < acc ? r.hora_inicio : acc), active[0].hora_inicio);
    const end = active.reduce((acc, r) => (r.hora_fim > acc ? r.hora_fim : acc), active[0].hora_fim);
    return { start: floorTo30(String(start).slice(0, 5)), end: ceilTo30(String(end).slice(0, 5)) };
});

function previewSlotLabelContent(arg) {
    const min = arg.date.getMinutes();
    if (min === 0) {
        const h = String(arg.date.getHours()).padStart(2, '0');
        return { html: `<span class="fc-slot-label-hour">${h}:00</span>` };
    }
    return { html: '<span class="fc-slot-label-half">:30</span>' };
}

const previewFcOptions = computed(() => {
    const day = previewDay.value;
    const base = day != null ? dateForDayOfWeek(day) : new Date();

    return {
        plugins: [timeGridPlugin],
        locale: ptBrLocale,
        initialView: 'timeGridDay',
        initialDate: base,
        headerToolbar: false,
        allDaySlot: false,
        slotMinTime: previewBounds.value.start + ':00',
        slotMaxTime: previewBounds.value.end + ':00',
        slotDuration: '00:15:00',
        snapDuration: '00:15:00',
        slotLabelInterval: '00:30',
        slotLabelContent: previewSlotLabelContent,
        expandRows: true,
        height: 'auto',
        editable: false,
        selectable: false,
        events: previewFcEvents.value
    };
});

// reage quando o dia muda
watch(previewDay, async () => {
    await nextTick();
    fcRef.value?.getApi?.()?.refetchEvents?.();
});
watch(
    previewFcEvents,
    async () => {
        await nextTick();
        fcRef.value?.getApi?.()?.refetchEvents?.();
    },
    { deep: true }
);

// presets de duração
const durationPresets = [
    { label: '30 min', dur: 30, gap: 0, off: 0 },
    { label: '45 min', dur: 45, gap: 15, off: 0 },
    { label: '50 min', dur: 50, gap: 10, off: 0 },
    { label: '60 min', dur: 60, gap: 0, off: 0 },
    { label: '90 min', dur: 90, gap: 0, off: 0 }
];

function applyDurationPreset(preset) {
    cfg.value.session_duration_min = preset.dur;
    cfg.value.session_break_min = preset.gap;
    showAdvancedRitmo.value = false;
}

function isActivePreset(preset) {
    return cfg.value.session_duration_min === preset.dur && cfg.value.session_break_min === preset.gap;
}

// computed para DatePicker bridge (ritmo: duração e intervalo em minutos)
const durationDate = computed({
    get: () => hhmmToDate(minToHHMM(Number(cfg.value.session_duration_min || 50))),
    set: (v) => {
        if (v instanceof Date) cfg.value.session_duration_min = v.getHours() * 60 + v.getMinutes();
    }
});
const breakDate = computed({
    get: () => hhmmToDate(minToHHMM(Number(cfg.value.session_break_min || 0))),
    set: (v) => {
        if (v instanceof Date) cfg.value.session_break_min = v.getHours() * 60 + v.getMinutes();
    }
});

// computed para DatePicker bridge (jornada global)
const jornadaStartDate = computed({
    get: () => hhmmToDate(jornadaStart.value),
    set: (v) => {
        const h = dateToHHMM(v);
        if (h) jornadaStart.value = h;
    }
});
const jornadaEndDate = computed({
    get: () => hhmmToDate(jornadaEnd.value),
    set: (v) => {
        const h = dateToHHMM(v);
        if (h) jornadaEnd.value = h;
    }
});
</script>

<template>
    <!-- ══ SKELETON ═══════════════════════════════════════════════ -->
    <div v-if="loading" class="flex flex-col xl:flex-row gap-4">
        <!-- Coluna esquerda skeleton -->
        <div class="flex flex-col gap-3 xl:w-[58%]">
            <!-- Subheader skeleton -->
            <div class="flex items-center gap-3 px-1 py-2">
                <Skeleton shape="circle" size="2rem" />
                <div class="flex flex-col gap-1.5">
                    <Skeleton width="9rem" height="0.85rem" />
                    <Skeleton width="14rem" height="0.75rem" />
                </div>
            </div>

            <!-- Card skeleton (×3) — frases dentro do primeiro -->
            <div v-for="i in 3" :key="i" class="rounded-[8px] border border-[var(--surface-border)] bg-[var(--surface-card)] shadow-sm">
                <div class="flex items-center gap-3 px-4 py-4">
                    <Skeleton shape="circle" size="2.2rem" />
                    <div class="flex-1 flex flex-col gap-1.5">
                        <Skeleton :width="i === 1 ? '11rem' : i === 2 ? '9rem' : '13rem'" height="0.85rem" />
                        <Skeleton :width="i === 1 ? '18rem' : i === 2 ? '12rem' : '10rem'" height="0.7rem" />
                    </div>
                    <Skeleton width="6rem" height="1.4rem" border-radius="999px" />
                    <Skeleton shape="circle" size="1rem" />
                </div>
                <AppLoadingPhrases v-if="i === 1" action="Carregando configurações da agenda..." containerClass="py-8" />
            </div>
        </div>

        <!-- Coluna direita: skeleton puro -->
        <div class="xl:w-[42%] xl:self-start">
            <div class="rounded-[6px] border border-[var(--surface-border)] bg-[var(--surface-card)] overflow-hidden shadow-sm">
                <!-- Header skeleton -->
                <div class="flex items-center justify-between px-4 py-3 border-b border-[var(--surface-border)]">
                    <Skeleton width="8rem" height="0.85rem" />
                    <div class="flex gap-1">
                        <Skeleton v-for="j in 5" :key="j" width="2.2rem" height="1.6rem" border-radius="999px" />
                    </div>
                </div>
                <!-- Legenda skeleton -->
                <div class="flex gap-3 px-4 py-2 border-b border-[var(--surface-border)]">
                    <Skeleton v-for="k in 3" :key="k" width="4.5rem" height="0.7rem" />
                </div>
                <!-- Calendário skeleton -->
                <div class="flex flex-col gap-2 p-4">
                    <Skeleton v-for="l in 10" :key="l" :width="`${70 + (l % 3) * 10}%`" height="2.2rem" />
                </div>
            </div>
        </div>
    </div>

    <Transition name="fade-up" appear>
        <div v-if="!loading" class="flex flex-col xl:flex-row gap-4">
            <!-- ══ COLUNA ESQUERDA: CARDS ══════════════════════════════ -->
            <div class="anim-child [--delay:0ms] flex flex-col gap-3 xl:w-[58%]">
                <!-- ── CARD 1: JORNADA ─────────────────────────────────── -->
                <div class="cfg-card" :class="{ 'cfg-card--open': expandedCard === 'jornada' }">
                    <!-- Cabeçalho clicável -->
                    <button class="cfg-card__header" @click="expandedCard = expandedCard === 'jornada' ? null : 'jornada'">
                        <div class="cfg-card__icon-wrap w-10 h-10 rounded-md">
                            <i class="pi pi-calendar text-lg" />
                        </div>
                        <div class="flex-1 min-w-0 text-left">
                            <div class="cfg-card__title">Horários de trabalho</div>
                            <div class="cfg-card__summary">{{ resumoJornada }}</div>
                        </div>
                        <div class="flex items-center gap-2">
                            <span v-if="jornadaOk" class="cfg-badge cfg-badge--ok"><i class="pi pi-check" /> Configurado</span>
                            <span v-else class="cfg-badge cfg-badge--warn"><i class="pi pi-exclamation-triangle" /> Pendente</span>
                            <i class="pi text-[var(--text-color-secondary)] transition-transform duration-200" :class="expandedCard === 'jornada' ? 'pi-chevron-up' : 'pi-chevron-down'" />
                        </div>
                    </button>

                    <!-- Corpo expansível -->
                    <div v-show="expandedCard === 'jornada'" class="cfg-card__body">
                        <div class="border-t border-[var(--surface-border)] pt-4">
                            <!-- Fuso horário -->
                            <div class="mb-5">
                                <div class="cfg-label mb-2">Fuso horário</div>
                                <Select v-model="cfg.timezone" :options="timezones" optionLabel="label" optionValue="value" class="w-full max-w-xs" placeholder="Selecione o fuso..." />
                            </div>

                            <!-- Dias da semana -->
                            <div class="mb-5">
                                <div class="cfg-label mb-2">Quais dias você trabalha?</div>
                                <div class="flex flex-wrap gap-2">
                                    <button
                                        v-for="d in diasSemana"
                                        :key="d.value"
                                        class="day-chip"
                                        :class="workDays[d.value] ? 'day-chip--active' : ''"
                                        @click="
                                            workDays[d.value] = !workDays[d.value];
                                            previewDay = selectedDays[0]?.value ?? previewDay;
                                        "
                                    >
                                        {{ d.short }}
                                    </button>
                                </div>
                            </div>

                            <!-- Horário -->
                            <div v-if="selectedDays.length > 0" class="mb-5">
                                <div class="cfg-label mb-3">Qual é o seu horário?</div>

                                <!-- Toggle igual/diferente por dia -->
                                <div class="flex gap-2 mb-4">
                                    <button class="toggle-opt" :class="jornadaIgualTodos !== false ? 'toggle-opt--active' : ''" @click="switchToIgual">Igual para todos os dias</button>
                                    <button class="toggle-opt" :class="jornadaIgualTodos === false ? 'toggle-opt--active' : ''" @click="switchToDiferente">Diferente por dia</button>
                                </div>

                                <!-- Igual para todos -->
                                <div v-if="jornadaIgualTodos !== false" class="flex flex-col gap-3">
                                    <!-- Seg–Sex -->
                                    <div v-if="selectedWeekdays.length > 0" class="cfg-equal-group">
                                        <div class="cfg-equal-chips">
                                            <span v-for="d in selectedWeekdays" :key="d.value" class="day-chip day-chip--active">{{ d.short }}</span>
                                        </div>
                                        <div class="flex items-center gap-2">
                                            <span class="text-sm text-[var(--text-color-secondary)]">Das</span>
                                            <div class="w-32">
                                                <DatePicker v-model="jornadaStartDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
                                                    <template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
                                                </DatePicker>
                                            </div>
                                            <span class="text-sm text-[var(--text-color-secondary)]">até</span>
                                            <div class="w-32">
                                                <DatePicker v-model="jornadaEndDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
                                                    <template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
                                                </DatePicker>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- Sábado -->
                                    <div v-if="workDays[6]" class="cfg-equal-group">
                                        <div class="cfg-equal-chips">
                                            <span class="day-chip day-chip--active">Sáb</span>
                                        </div>
                                        <div class="flex items-center gap-2">
                                            <span class="text-sm text-[var(--text-color-secondary)]">Das</span>
                                            <div class="w-32">
                                                <DatePicker
                                                    :modelValue="hhmmToDate(jornadaPorDia[6]?.inicio)"
                                                    @update:modelValue="
                                                        (v) => {
                                                            const h = dateToHHMM(v);
                                                            if (h) jornadaPorDia[6] = { ...jornadaPorDia[6], inicio: h };
                                                        }
                                                    "
                                                    showIcon
                                                    fluid
                                                    iconDisplay="input"
                                                    timeOnly
                                                    hourFormat="24"
                                                    :stepMinute="15"
                                                    :manualInput="false"
                                                >
                                                    <template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
                                                </DatePicker>
                                            </div>
                                            <span class="text-sm text-[var(--text-color-secondary)]">até</span>
                                            <div class="w-32">
                                                <DatePicker
                                                    :modelValue="hhmmToDate(jornadaPorDia[6]?.fim)"
                                                    @update:modelValue="
                                                        (v) => {
                                                            const h = dateToHHMM(v);
                                                            if (h) jornadaPorDia[6] = { ...jornadaPorDia[6], fim: h };
                                                        }
                                                    "
                                                    showIcon
                                                    fluid
                                                    iconDisplay="input"
                                                    timeOnly
                                                    hourFormat="24"
                                                    :stepMinute="15"
                                                    :manualInput="false"
                                                >
                                                    <template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
                                                </DatePicker>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- Domingo -->
                                    <div v-if="workDays[0]" class="cfg-equal-group">
                                        <div class="cfg-equal-chips">
                                            <span class="day-chip day-chip--active">Dom</span>
                                        </div>
                                        <div class="flex items-center gap-2">
                                            <span class="text-sm text-[var(--text-color-secondary)]">Das</span>
                                            <div class="w-32">
                                                <DatePicker
                                                    :modelValue="hhmmToDate(jornadaPorDia[0]?.inicio)"
                                                    @update:modelValue="
                                                        (v) => {
                                                            const h = dateToHHMM(v);
                                                            if (h) jornadaPorDia[0] = { ...jornadaPorDia[0], inicio: h };
                                                        }
                                                    "
                                                    showIcon
                                                    fluid
                                                    iconDisplay="input"
                                                    timeOnly
                                                    hourFormat="24"
                                                    :stepMinute="15"
                                                    :manualInput="false"
                                                >
                                                    <template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
                                                </DatePicker>
                                            </div>
                                            <span class="text-sm text-[var(--text-color-secondary)]">até</span>
                                            <div class="w-32">
                                                <DatePicker
                                                    :modelValue="hhmmToDate(jornadaPorDia[0]?.fim)"
                                                    @update:modelValue="
                                                        (v) => {
                                                            const h = dateToHHMM(v);
                                                            if (h) jornadaPorDia[0] = { ...jornadaPorDia[0], fim: h };
                                                        }
                                                    "
                                                    showIcon
                                                    fluid
                                                    iconDisplay="input"
                                                    timeOnly
                                                    hourFormat="24"
                                                    :stepMinute="15"
                                                    :manualInput="false"
                                                >
                                                    <template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
                                                </DatePicker>
                                            </div>
                                        </div>
                                    </div>
                                </div>

                                <!-- Diferente por dia -->
                                <div v-else class="flex flex-col gap-2">
                                    <div v-for="d in selectedDays" :key="d.value" class="flex items-center gap-3 p-2 rounded-[6px] bg-[var(--surface-ground)]">
                                        <span class="w-10 text-sm font-medium">{{ d.short }}</span>
                                        <div class="w-32">
                                            <DatePicker
                                                :modelValue="hhmmToDate(jornadaPorDia[d.value]?.inicio)"
                                                @update:modelValue="
                                                    (v) => {
                                                        const h = dateToHHMM(v);
                                                        if (h) {
                                                            jornadaPorDia[d.value] = { ...jornadaPorDia[d.value], inicio: h };
                                                            previewDay = d.value;
                                                        }
                                                    }
                                                "
                                                showIcon
                                                fluid
                                                iconDisplay="input"
                                                timeOnly
                                                hourFormat="24"
                                                :stepMinute="15"
                                                :manualInput="false"
                                            >
                                                <template #inputicon="slotProps">
                                                    <i class="pi pi-clock" @click="slotProps.clickCallback" />
                                                </template>
                                            </DatePicker>
                                        </div>
                                        <span class="text-sm text-[var(--text-color-secondary)]">até</span>
                                        <div class="w-32">
                                            <DatePicker
                                                :modelValue="hhmmToDate(jornadaPorDia[d.value]?.fim)"
                                                @update:modelValue="
                                                    (v) => {
                                                        const h = dateToHHMM(v);
                                                        if (h) {
                                                            jornadaPorDia[d.value] = { ...jornadaPorDia[d.value], fim: h };
                                                            previewDay = d.value;
                                                        }
                                                    }
                                                "
                                                showIcon
                                                fluid
                                                iconDisplay="input"
                                                timeOnly
                                                hourFormat="24"
                                                :stepMinute="15"
                                                :manualInput="false"
                                            >
                                                <template #inputicon="slotProps">
                                                    <i class="pi pi-clock" @click="slotProps.clickCallback" />
                                                </template>
                                            </DatePicker>
                                        </div>
                                    </div>
                                </div>
                            </div>

                            <!-- Pausas -->
                            <div v-if="selectedDays.length > 0" class="mb-5">
                                <div class="cfg-label mb-2">Pausas (opcional)</div>
                                <div class="text-sm text-[var(--text-color-secondary)] mb-3">Ex.: almoço, jantar, etc.</div>

                                <div v-if="jornadaIgualTodos !== false">
                                    <PausasChipsEditor v-model="pausasGlobais" />
                                </div>
                                <div v-else class="flex flex-col gap-3">
                                    <div v-for="d in selectedDays" :key="d.value">
                                        <div class="text-xs font-semibold mb-1 text-[var(--text-color-secondary)]">{{ d.label }}</div>
                                        <PausasChipsEditor v-model="pausasPorDia[d.value]" />
                                    </div>
                                </div>
                            </div>

                            <!-- Ação -->
                            <div class="flex justify-end">
                                <Button label="Salvar jornada" icon="pi pi-check" :loading="savingCard === 'jornada'" :disabled="!jornadaOk || !!savingCard" class="rounded-full" @click="saveJornada" />
                            </div>
                        </div>
                    </div>
                </div>

                <!-- ── CARD 2: RITMO ───────────────────────────────────── -->
                <div class="cfg-card" :class="{ 'cfg-card--open': expandedCard === 'ritmo' }">
                    <button class="cfg-card__header" @click="expandedCard = expandedCard === 'ritmo' ? null : 'ritmo'">
                        <div class="cfg-card__icon-wrap w-10 h-10 rounded-md">
                            <i class="pi pi-stopwatch text-lg" />
                        </div>
                        <div class="flex-1 min-w-0 text-left">
                            <div class="cfg-card__title">Ritmo das sessões</div>
                            <div class="cfg-card__summary">{{ resumoRitmo }}</div>
                        </div>
                        <div class="flex items-center gap-2">
                            <span class="cfg-badge cfg-badge--ok"><i class="pi pi-check" /> Configurado</span>
                            <i class="pi text-[var(--text-color-secondary)] transition-transform duration-200" :class="expandedCard === 'ritmo' ? 'pi-chevron-up' : 'pi-chevron-down'" />
                        </div>
                    </button>

                    <div v-show="expandedCard === 'ritmo'" class="cfg-card__body">
                        <div class="border-t border-[var(--surface-border)] pt-4">
                            <!-- Presets -->
                            <div class="mb-5">
                                <div class="cfg-label mb-3">Duração padrão das sessões</div>
                                <div class="flex flex-wrap gap-2">
                                    <button v-for="p in durationPresets" :key="p.label" class="preset-chip" :class="isActivePreset(p) ? 'preset-chip--active' : ''" @click="applyDurationPreset(p)">
                                        {{ p.label }}
                                        <span v-if="p.gap > 0" class="text-xs opacity-70 ml-1">· {{ p.gap }}min intervalo</span>
                                        <span v-else class="text-xs opacity-70 ml-1">· sem pausa</span>
                                    </button>
                                    <button class="preset-chip" :class="!durationPresets.some((p) => isActivePreset(p)) ? 'preset-chip--active' : ''" @click="showAdvancedRitmo = true">Personalizar</button>
                                </div>
                            </div>

                            <!-- Campos manuais (personalizado) -->
                            <div v-if="showAdvancedRitmo || !durationPresets.some((p) => isActivePreset(p))" class="mb-5 p-4 rounded-[6px] bg-[var(--surface-ground)]">
                                <div class="cfg-label mb-3">Personalizado</div>
                                <div class="flex flex-row gap-6">
                                    <div class="flex flex-col gap-1">
                                        <label class="text-xs text-[var(--text-color-secondary)]">Duração</label>
                                        <DatePicker v-model="durationDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="5" :manualInput="false">
                                            <template #inputicon="slotProps">
                                                <i class="pi pi-clock" @click="slotProps.clickCallback" />
                                            </template>
                                        </DatePicker>
                                    </div>
                                    <div class="flex flex-col gap-1">
                                        <label class="text-xs text-[var(--text-color-secondary)]">Intervalo</label>
                                        <DatePicker v-model="breakDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="5" :manualInput="false">
                                            <template #inputicon="slotProps">
                                                <i class="pi pi-clock" @click="slotProps.clickCallback" />
                                            </template>
                                        </DatePicker>
                                    </div>
                                </div>
                            </div>

                            <div class="flex justify-end">
                                <Button label="Salvar ritmo" icon="pi pi-check" :loading="savingCard === 'ritmo'" :disabled="!!savingCard" class="rounded-full" @click="saveRitmo" />
                            </div>
                        </div>
                    </div>
                </div>

                <!-- ── CARD 3: ONLINE ──────────────────────────────────── -->
                <div class="cfg-card" :class="{ 'cfg-card--open': expandedCard === 'online' }">
                    <button class="cfg-card__header" @click="expandedCard = expandedCard === 'online' ? null : 'online'">
                        <div class="cfg-card__icon-wrap w-10 h-10 rounded-md">
                            <i class="pi pi-globe text-lg" />
                        </div>
                        <div class="flex-1 min-w-0 text-left">
                            <div class="cfg-card__title">Agendamento online</div>
                            <div class="cfg-card__summary">{{ resumoOnline }}</div>
                        </div>
                        <div class="flex items-center gap-2">
                            <span v-if="cfg.online_ativo" class="cfg-badge cfg-badge--ok"><i class="pi pi-check" /> Configurado</span>
                            <span class="cfg-badge" :class="cfg.online_ativo ? 'cfg-badge--ok' : 'cfg-badge--off'">
                                {{ cfg.online_ativo ? 'Ativo' : 'Desativado' }}
                            </span>
                            <i class="pi text-[var(--text-color-secondary)] transition-transform duration-200" :class="expandedCard === 'online' ? 'pi-chevron-up' : 'pi-chevron-down'" />
                        </div>
                    </button>

                    <div v-show="expandedCard === 'online'" class="cfg-card__body">
                        <div class="border-t border-[var(--surface-border)] pt-4">
                            <!-- Aviso slots órfãos -->
                            <div v-if="orphanSlotDays.length" class="flex items-start gap-2 mb-4 p-3 rounded-[6px] bg-[var(--yellow-50)] border border-[var(--yellow-200)] text-sm text-[var(--yellow-800)]">
                                <i class="pi pi-exclamation-triangle mt-0.5 shrink-0" />
                                <span>
                                    Há slots configurados para <b>{{ orphanSlotDays.join(', ') }}</b
                                    >, mas esses dias não estão mais na sua jornada. Eles serão removidos automaticamente ao salvar a jornada.
                                </span>
                            </div>

                            <!-- Toggle ativo -->
                            <div class="flex items-center justify-between mb-5 p-4 rounded-[6px] bg-[var(--surface-ground)]">
                                <div>
                                    <div class="font-medium">Permitir que pacientes agendem online</div>
                                    <div class="text-sm text-[var(--text-color-secondary)] mt-0.5">Você escolhe quais horários ficam disponíveis.</div>
                                </div>
                                <button class="toggle-switch" :class="cfg.online_ativo ? 'toggle-switch--on' : ''" @click="cfg.online_ativo = !cfg.online_ativo">
                                    <span class="toggle-switch__thumb" />
                                </button>
                            </div>

                            <!-- Slots por dia -->
                            <div v-if="cfg.online_ativo && selectedDays.length">
                                <div class="cfg-label mb-3">Escolha os horários disponíveis</div>

                                <div class="online-tab-panel" :class="previewDay != null ? 'online-tab-panel--active' : ''">
                                    <!-- Seletor de dia (tabs) -->
                                    <div class="flex gap-2 flex-wrap p-3 pb-2">
                                        <button
                                            v-for="d in selectedDays"
                                            :key="d.value"
                                            class="online-day-tab"
                                            :class="{
                                                'online-day-tab--active': previewDay === d.value,
                                                'online-day-tab--has-slots': previewDay !== d.value && (onlineSlotsByDay[d.value]?.size || 0) > 0
                                            }"
                                            @click="previewDay = d.value"
                                        >
                                            {{ d.short }}
                                        </button>
                                    </div>

                                    <!-- Conteúdo do dia selecionado -->
                                    <template v-if="previewDay != null">
                                        <!-- Área cinza: ações rápidas + slots -->
                                        <div class="mx-3 mb-2 p-3 rounded-[6px] bg-[var(--surface-ground)]">
                                            <div v-if="(slotsByDay[previewDay] || []).length === 0" class="text-sm text-[var(--text-color-secondary)] py-1">Nenhum slot disponível para este dia. Configure a jornada primeiro.</div>
                                            <div v-else>
                                                <!-- Ações rápidas -->
                                                <div class="flex flex-wrap gap-2 mb-3">
                                                    <button
                                                        v-for="p in periodos"
                                                        :key="p.label"
                                                        v-show="hasSlotsInPeriodo(previewDay, p)"
                                                        class="periodo-btn"
                                                        :class="isPeriodoAtivo(previewDay, p) ? 'periodo-btn--on' : ''"
                                                        @click="togglePeriodo(previewDay, p)"
                                                    >
                                                        <i :class="['pi', p.icon, 'text-xs']" />
                                                        {{ p.label }}
                                                    </button>
                                                    <span class="w-px bg-[var(--surface-border)] self-stretch mx-1" />
                                                    <button class="periodo-btn" @click="enableAllDay(previewDay)">Todos</button>
                                                    <button class="periodo-btn" @click="clearDay(previewDay)">Limpar</button>
                                                </div>

                                                <!-- Slots individuais -->
                                                <div class="flex flex-wrap gap-2">
                                                    <button v-for="s in slotsByDay[previewDay] || []" :key="s.hhmm" class="slot-chip" :class="isSlotEnabled(previewDay, s.hhmm) ? 'slot-chip--on' : ''" @click="toggleSlot(previewDay, s.hhmm)">
                                                        {{ s.hhmm }}
                                                    </button>
                                                </div>
                                            </div>
                                        </div>

                                        <!-- Resumo fora da área cinza -->
                                        <div class="px-3 pb-3 text-xs text-[var(--text-color-secondary)]">
                                            <i class="pi pi-info-circle mr-1" />
                                            Há {{ onlineSlotsByDay[previewDay]?.size || 0 }} slot{{ (onlineSlotsByDay[previewDay]?.size || 0) !== 1 ? 's' : '' }} disponíveis para atendimento online toda
                                            {{ diasSemana.find((d) => d.value === previewDay)?.label?.toLowerCase() }}.
                                        </div>
                                    </template>
                                </div>
                            </div>

                            <div v-else-if="!selectedDays.length" class="text-sm text-[var(--text-color-secondary)] py-2">Configure sua jornada de trabalho primeiro.</div>

                            <div class="flex justify-end mt-4">
                                <Button label="Salvar" icon="pi pi-check" :loading="savingCard === 'online'" :disabled="!!savingCard" class="rounded-full" @click="saveOnline" />
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Bloco pós-carregamento -->
                <LoadedPhraseBlock />
            </div>

            <!-- ══ COLUNA DIREITA: PREVIEW ═════════════════════════════ -->
            <div class="anim-child [--delay:120ms] xl:w-[42%] xl:top-4 xl:self-start">
                <div class="rounded-[6px] border border-[var(--surface-border)] bg-[var(--surface-card)] overflow-hidden shadow-sm agenda-altura">
                    <!-- Header do preview -->
                    <div class="sticky top-0 z-10 bg-[var(--surface-card)]">
                        <div class="flex items-center justify-between px-4 py-3 border-b border-[var(--surface-border)]">
                            <div class="font-semibold text-sm">Preview da agenda</div>
                            <div class="flex gap-1">
                                <button v-for="d in selectedDays" :key="d.value" class="day-chip day-chip--sm" :class="jornadaIgualTodos !== false || previewDay === d.value ? 'day-chip--active' : ''" @click="previewDay = d.value">
                                    {{ d.short }}
                                </button>
                                <span v-if="!selectedDays.length" class="text-xs text-[var(--text-color-secondary)]"> Nenhum dia selecionado </span>
                            </div>
                        </div>

                        <!-- Legenda -->
                        <div class="flex gap-3 px-4 py-2 border-b border-[var(--surface-border)] text-xs text-[var(--text-color-secondary)]">
                            <span class="flex items-center gap-1"><span class="w-3 h-3 rounded bg-[var(--green-100)] inline-block border border-green-300"></span> Jornada</span>
                            <span class="flex items-center gap-1"><span class="w-3 h-3 rounded bg-[var(--red-200)] inline-block border border-red-300"></span> Pausa</span>
                            <span class="flex items-center gap-1"><span class="w-3 h-3 rounded bg-[var(--primary-color)] inline-block"></span> Sessão</span>
                            <span v-if="cfg.online_ativo" class="flex items-center gap-1">🌐 Online</span>
                        </div>
                    </div>

                    <!-- FullCalendar -->
                    <div v-if="previewDay != null && !loading" class="p-2">
                        <FullCalendar ref="fcRef" :key="`preview-${previewDay}-${previewBounds.start}-${previewBounds.end}`" :options="previewFcOptions" />
                    </div>
                    <div v-else class="flex items-center justify-center py-16 text-[var(--text-color-secondary)] text-sm">Selecione um dia de trabalho para ver o preview.</div>
                </div>
            </div>
        </div>
    </Transition>
</template>

<style>
.fc-slot-label-hour {
    display: inline-block;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--text-color);
    letter-spacing: -0.01em;
    line-height: 1;
}
.fc-slot-label-half {
    display: inline-block;
    font-size: 0.68rem;
    font-weight: 400;
    color: var(--text-color-secondary);
    opacity: 0.5;
    line-height: 1;
    padding-left: 2px;
}
</style>

<style scoped>
/* ── Cards ─────────────────────────────────────────────────── */
.cfg-card {
    border-radius: 6px;
    border: 1px solid var(--surface-border);
    background: var(--surface-card);
    overflow: hidden;
    transition: box-shadow 0.2s ease;
}
.cfg-card--open {
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
}
.cfg-card__header {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    width: 100%;
    padding: 1rem 1.25rem;
    background: transparent;
    border: none;
    cursor: pointer;
    transition: background 0.15s;
}
.cfg-card__header:hover {
    background: var(--surface-hover);
}

.cfg-card__title {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text-color);
    line-height: 1.2;
}
.cfg-card__summary {
    font-size: 0.8125rem;
    color: var(--text-color-secondary);
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 28ch;
}
.cfg-card__body {
    padding: 0 1.25rem 1.25rem;
}

/* ── Badges ─────────────────────────────────────────────────── */
.cfg-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.2rem 0.55rem;
    border-radius: 99px;
    white-space: nowrap;
}
.cfg-badge--ok {
    background: var(--green-100);
    color: var(--green-700);
}
.cfg-badge--warn {
    background: var(--yellow-100);
    color: var(--yellow-700);
}
.cfg-badge--off {
    background: var(--surface-200);
    color: var(--text-color-secondary);
}

/* ── Labels ─────────────────────────────────────────────────── */
.cfg-label {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text-color-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* ── Day chips ──────────────────────────────────────────────── */
.day-chip {
    padding: 0.35rem 0.75rem;
    border-radius: 99px;
    border: 1.5px solid var(--surface-border);
    background: var(--surface-ground);
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
    color: var(--text-color);
}
.day-chip:hover {
    border-color: var(--primary-color);
}
.day-chip--active {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
}
.day-chip--sm {
    padding: 0.2rem 0.55rem;
    font-size: 0.75rem;
}
.cfg-equal-group {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}
.cfg-equal-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    min-width: 200px;
}

/* ── Toggle opções ──────────────────────────────────────────── */
.toggle-opt {
    flex: 1;
    padding: 0.5rem 1rem;
    border-radius: 0.75rem;
    border: 1.5px solid var(--surface-border);
    background: var(--surface-ground);
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
    color: var(--text-color-secondary);
}
.toggle-opt:hover {
    border-color: var(--primary-color);
    color: var(--text-color);
}
.toggle-opt--active {
    border-color: var(--primary-color);
    background: color-mix(in srgb, var(--primary-color) 10%, transparent);
    color: var(--primary-color);
    font-weight: 600;
}

/* ── Preset chips ───────────────────────────────────────────── */
.preset-chip {
    padding: 0.45rem 1rem;
    border-radius: 99px;
    border: 1.5px solid var(--surface-border);
    background: var(--surface-ground);
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
    color: var(--text-color);
}
.preset-chip:hover {
    border-color: var(--primary-color);
}
.preset-chip--active {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
}

/* ── Período buttons ────────────────────────────────────────── */
.periodo-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.75rem;
    border-radius: 99px;
    border: 1.5px solid var(--surface-border);
    background: var(--surface-ground);
    font-size: 0.8rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
    color: var(--text-color-secondary);
}
.periodo-btn:hover {
    border-color: var(--primary-color);
    color: var(--text-color);
}
.periodo-btn--on {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
    font-weight: 600;
}

/* ── Slot chips ─────────────────────────────────────────────── */
.slot-chip {
    padding: 0.3rem 0.7rem;
    border-radius: 0.625rem;
    border: 1.5px solid var(--surface-border);
    background: var(--surface-ground);
    font-size: 0.8rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
    color: var(--text-color-secondary);
    font-family: monospace;
}
.slot-chip:hover {
    border-color: var(--primary-color);
}
.slot-chip--on {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
}

/* ── Online tab panel ───────────────────────────────────────── */
.online-tab-panel {
    border-radius: 12px;
}

.online-day-tab {
    padding: 0.3rem 0.7rem;
    border-radius: 99px;
    border: 1.5px solid var(--surface-border);
    background: var(--surface-card);
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
    color: var(--text-color-secondary);
    transition: all 0.15s;
}
.online-day-tab:hover {
    border-color: var(--primary-color);
}
.online-day-tab--has-slots {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
    font-weight: 600;
}
.online-day-tab--active {
    background: var(--primary-color);
    border-color: var(--primary-color);
    color: #fff;
    font-weight: 700;
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* ── Toggle switch ──────────────────────────────────────────── */
.toggle-switch {
    width: 2.75rem;
    height: 1.5rem;
    border-radius: 99px;
    background: var(--surface-300);
    border: none;
    cursor: pointer;
    position: relative;
    transition: background 0.2s;
    flex-shrink: 0;
}
.toggle-switch--on {
    background: var(--primary-color);
}
.toggle-switch__thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 1.125rem;
    height: 1.125rem;
    border-radius: 50%;
    background: #fff;
    transition: transform 0.2s;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.toggle-switch--on .toggle-switch__thumb {
    transform: translateX(1.25rem);
}
</style>
