<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/views/pages/therapist/TherapistDashboard.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<template>
  <div class="flex min-h-[calc(100vh-4.5rem)] bg-[var(--surface-ground,#f5f7fa)]">

    <!-- ═══════════════════════════════════════
         OVERLAY (mobile) + ASIDE
    ══════════════════════════════════════════ -->
    <div
      v-if="asideOpen"
      class="fixed inset-0 bg-black/40 backdrop-blur-sm z-[39] xl:hidden"
      @click="asideOpen = false"
    />

    <aside
      class="aside-drawer flex flex-col overflow-y-auto flex-shrink-0
             bg-[var(--surface-card,#fff)] border-r border-[var(--surface-border,#e2e8f0)]"
      :class="asideOpen ? 'translate-x-0 visible' : 'max-xl:-translate-x-full max-xl:invisible'"
    >
      <!-- Mini calendário -->
      <div class="p-3.5 pb-2.5 border-b border-[var(--surface-border,#e2e8f0)]">
        <div class="flex items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary,#64748b)] mb-2.5">
          <i class="pi pi-calendar" />
          <span>Março 2026</span>
        </div>

        <!-- Skeleton -->
        <template v-if="loading">
          <div class="grid grid-cols-7 mb-0.5">
            <Skeleton v-for="n in 7" :key="n" height="14px" class="mx-0.5" />
          </div>
          <div class="grid grid-cols-7 gap-px mt-1">
            <Skeleton v-for="n in 35" :key="n" height="22px" class="rounded" />
          </div>
        </template>

        <template v-else>
          <div class="grid grid-cols-7 mb-0.5">
            <span v-for="d in diasSemana" :key="d" class="text-center text-xs font-bold text-[var(--text-color-secondary,#94a3b8)] py-0.5">{{ d }}</span>
          </div>
          <div class="grid grid-cols-7 gap-px">
            <button
              v-for="cell in calCells"
              :key="cell.key"
              class="relative aspect-square flex items-center justify-center text-xs font-medium rounded border-none cursor-pointer transition-colors duration-100"
              :class="{
                'bg-[var(--primary-color,#6366f1)] text-white font-bold rounded-md': cell.isToday,
                'text-[var(--text-color-secondary,#cbd5e1)] cursor-default': cell.isOther,
                'bg-indigo-500/10 text-[var(--primary-color,#6366f1)] font-bold': cell.day === selectedDay && !cell.isToday,
                'text-[var(--text-color,#1e293b)] hover:bg-[var(--surface-hover,#f1f5f9)]': !cell.isToday && !cell.isOther,
              }"
              @click="cell.day && onCalDayClick($event, cell.day)"
            >
              <span>{{ cell.day }}</span>
              <span
                v-if="cell.count"
                class="absolute bottom-px right-0.5 w-1 h-1 rounded-full"
                :class="{
                  'bg-red-500':   cell.urgency === 'urg-alta',
                  'bg-amber-500': cell.urgency === 'urg-media',
                  'bg-green-500': cell.urgency === 'urg-baixa',
                }"
              />
            </button>
          </div>
        </template>
      </div>

      <!-- Eventos do dia -->
      <div class="p-3.5 pb-2.5 border-b border-[var(--surface-border,#e2e8f0)]">
        <div class="flex items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary,#64748b)] mb-2.5">
          <i class="pi pi-clock" /><span>{{ labelDiaSelecionado }}</span>
        </div>

        <!-- Skeleton -->
        <template v-if="loading">
          <div class="flex flex-col gap-2">
            <div v-for="n in 3" :key="n" class="aside-ev aside-ev--skeleton">
              <div class="flex flex-col gap-1 min-w-[36px] items-end">
                <Skeleton width="32px" height="10px" />
                <Skeleton width="24px" height="8px" />
              </div>
              <Skeleton shape="square" size="28px" border-radius="4px" />
              <div class="flex flex-col gap-1.5 flex-1">
                <Skeleton :width="n === 1 ? '75%' : n === 2 ? '60%' : '70%'" height="10px" />
                <Skeleton width="40%" height="8px" />
              </div>
            </div>
          </div>
        </template>

        <div v-else class="flex flex-col gap-2 max-h-[260px] overflow-y-auto pr-0.5">
          <div
            v-for="ev in eventosDoDia"
            :key="ev.id"
            class="aside-ev"
            :style="ev.bgColor ? { '--ev-color': ev.bgColor } : {}"
            :class="{
              'aside-ev--reuniao':   !ev.bgColor && ev.tipo === 'reuniao',
              'aside-ev--realizado': !ev.bgColor && ev.status === 'realizado',
              'aside-ev--default':   !ev.bgColor && ev.tipo !== 'reuniao' && ev.status !== 'realizado',
            }"
            @click="openEvMenu($event, ev)"
          >
            <div class="aside-ev__time">
              <span class="aside-ev__hora">{{ ev.hora }}</span>
              <span class="aside-ev__dur">{{ ev.dur }}</span>
            </div>
            <Avatar :label="initials(ev.nome)" shape="square" size="small" class="flex-shrink-0" />
            <div class="flex-1 min-w-0">
              <span class="block text-[0.8125rem] font-semibold truncate text-[var(--text-color)]">{{ ev.nome }}</span>
              <div class="flex gap-1.5 mt-0.5 items-center">
                <span class="aside-ev__badge">{{ ev.modalidade }}</span>
                <i v-if="ev.recorrente" class="pi pi-sync text-[0.6rem] text-[var(--primary-color,#6366f1)]" title="Recorrente" />
              </div>
            </div>
            <i :class="ev.statusIcon" class="text-xs text-[var(--text-color-secondary)] flex-shrink-0" />
          </div>
          <div v-if="!eventosDoDia.length" class="flex items-center gap-2 py-3 text-[var(--text-color-secondary)] text-sm">
            <i class="pi pi-sun" /><span>Sem compromissos</span>
          </div>
        </div>
      </div>

      <!-- Recorrências ativas -->
      <div class="p-3.5 pb-2.5 border-b border-[var(--surface-border,#e2e8f0)]">
        <div class="flex items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary,#64748b)] mb-2.5">
          <i class="pi pi-sync" /><span>Recorrências ativas</span>
          <span class="ml-auto bg-[var(--primary-color,#6366f1)] text-white rounded-full px-1.5 text-xs font-bold">{{ recorrencias.length }}</span>
        </div>

        <!-- Skeleton -->
        <template v-if="loading">
          <div class="flex flex-col gap-2">
            <div v-for="n in 4" :key="n" class="aside-rec aside-rec--skeleton">
              <Skeleton shape="square" size="30px" border-radius="4px" />
              <div class="flex flex-col gap-1.5 flex-1">
                <Skeleton :width="n % 2 === 0 ? '65%' : '50%'" height="10px" />
                <Skeleton width="75%" height="8px" />
              </div>
              <Skeleton width="28px" height="10px" />
            </div>
          </div>
        </template>

        <div v-else class="flex flex-col gap-1.5 max-h-[210px] overflow-y-auto pr-0.5">
          <div
            v-for="r in recorrencias"
            :key="r.id"
            class="aside-rec"
            @click="openRecMenu($event, r)"
          >
            <Avatar :label="r.initials" shape="square" size="normal" class="flex-shrink-0" />
            <div class="flex-1 min-w-0">
              <span class="block text-[0.8125rem] font-semibold truncate text-[var(--text-color)]">{{ r.nome }}</span>
              <span class="block text-xs text-[var(--text-color-secondary)]">{{ r.freq }}</span>
            </div>
            <div
              class="aside-rec__prox"
              :class="r.proxHoje ? 'text-[var(--primary-color,#6366f1)] font-bold' : 'text-[var(--text-color-secondary)]'"
            >{{ r.proxLabel }}</div>
          </div>
          <div v-if="!recorrencias.length" class="flex items-center gap-2 py-3 text-[var(--text-color-secondary)] text-sm">
            <i class="pi pi-info-circle" /><span>Nenhuma recorrência ativa</span>
          </div>
        </div>
      </div>
    </aside>

    <!-- ═══════════════════════════════════════
         CONTEÚDO PRINCIPAL
    ══════════════════════════════════════════ -->
    <div ref="dashHeroSentinelRef" class="h-px" />

    <main class="flex-1 min-w-0 p-4 xl:p-[1.125rem_1.375rem] flex flex-col gap-4 overflow-y-auto">

      <!-- Hero Header -->
      <!-- Skeleton hero -->
      <section v-if="loading" class="relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-2.5">
        <div class="flex items-center gap-3 mb-3">
          <Skeleton width="40px" height="40px" border-radius="8px" />
          <div class="flex flex-col gap-1.5 flex-1">
            <Skeleton width="12rem" height="14px" />
            <Skeleton width="18rem" height="11px" />
          </div>
          <Skeleton width="36px" height="36px" border-radius="999px" />
          <Skeleton width="36px" height="36px" border-radius="999px" />
        </div>
        <div class="flex flex-wrap gap-2.5">
          <div v-for="n in 4" :key="n" class="flex flex-col gap-1.5 px-4 py-2.5 rounded-md border border-[var(--surface-border)] flex-1 min-w-[90px]">
            <Skeleton width="2rem" height="20px" />
            <Skeleton width="4rem" height="10px" />
          </div>
        </div>
      </section>

      <section
        v-if="!loading"
        class="relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-2.5"
        :class="{ 'rounded-tl-none rounded-tr-none': heroStuck }"
      >
        <div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
          <div class="absolute w-72 h-72 -top-16 -right-12 rounded-full blur-[70px] bg-indigo-500/10" />
          <div class="absolute w-80 h-80 top-2 -left-20 rounded-full blur-[70px] bg-emerald-400/[0.08]" />
        </div>

        <!-- Linha 1 -->
        <div class="relative z-[1] flex items-center gap-4">
          <div class="flex items-center gap-3 flex-1 min-w-0">
            <div class="grid place-items-center w-10 h-10 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
              <i class="pi pi-home text-lg" />
            </div>
            <div class="min-w-0">
              <div class="text-[1.1rem] font-bold tracking-tight text-[var(--text-color-secondary)]">{{ saudacao }} <span class="text-[var(--primary-color,#6366f1)]">👋</span></div>
              <div class="text-[0.78rem] text-[var(--text-color-secondary)] mt-0.5">{{ resumoHoje }}</div>
            </div>
          </div>
          <!-- Controles (desktop e mobile — mesmo conteúdo, sempre visível) -->
          <div class="flex items-center gap-2 flex-shrink-0">
            <Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Recarregar" @click="load" />
            <Button icon="pi pi-cog" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Configurações" @click="$router.push('/configuracoes')" />
          </div>
        </div>

        <Divider class="hidden xl:block my-2" />

        <!-- Quick stats -->
        <div class="relative z-[1] mt-2">
          <div class="flex flex-wrap gap-2.5">
            <div
              v-for="s in quickStats"
              :key="s.label"
              class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[90px] text-center xl:text-left transition-colors duration-150"
              :class="{
                'border-red-500/25 bg-red-500/5':    s.cls === 'qs-urgente',
                'border-green-500/25 bg-green-500/5': s.cls === 'qs-ok',
                'border-[var(--surface-border)] bg-[var(--surface-ground)]': !s.cls,
              }"
            >
              <div
                class="text-[1.35rem] font-bold leading-none"
                :class="{
                  'text-red-500':   s.cls === 'qs-urgente',
                  'text-green-500': s.cls === 'qs-ok',
                  'text-[var(--text-color)]': !s.cls,
                }"
              >{{ s.value }}</div>
              <div class="text-[0.7rem] text-[var(--text-color-secondary)] opacity-75">{{ s.label }}</div>
            </div>
          </div>
        </div>
      </section>

      <!-- Toggle aside — só mobile -->
      <button
        class="xl:hidden flex w-full items-center justify-between gap-3 px-4 py-3 bg-[var(--surface-card,#fff)] border-b border-[var(--surface-border,#e2e8f0)] text-sm font-semibold text-[var(--text-color)] cursor-pointer sticky top-0 z-30"
        @click="asideOpen = !asideOpen"
      >
        <div class="flex items-center gap-2 min-w-0">
          <i class="pi pi-calendar-clock text-[var(--primary-color,#6366f1)]" />
          <span class="truncate">Agenda · {{ labelDiaSelecionado }}</span>
          <span v-if="eventosDoDia.length" class="inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-xs font-bold flex-shrink-0">{{ eventosDoDia.length }}</span>
        </div>
        <i class="pi transition-transform duration-200" :class="asideOpen ? 'pi-chevron-up' : 'pi-chevron-down'" />
      </button>

      <!-- Linha do tempo -->
      <section v-if="loading" class="bg-[var(--surface-card)] rounded-md border border-[var(--surface-border)] p-2.5">
        <div class="flex items-center justify-between mb-2.5">
          <Skeleton width="12rem" height="12px" />
          <Skeleton width="6rem" height="12px" />
        </div>
        <Skeleton width="100%" height="40px" border-radius="6px" class="mt-2.5" />
      </section>

      <section v-if="!loading" class="bg-[var(--surface-card,#fff)] rounded-md border border-[var(--surface-border,#e2e8f0)] p-2.5 shadow-[0_0_0_3px_color-mix(in_srgb,var(--primary-color)_7%,transparent)]">
        <div class="flex items-center justify-between mb-2.5">
		  <div class="flex items-center gap-2.5">
			<i class="pi pi-chart-bar w-10 h-10 rounded-md cfg-subheader__icon flex-shrink-0" />

			<div class="flex flex-col leading-tight">
			  <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">
				Linha do tempo — Hoje
			  </div>
			  <div class="text-xs font-semibold text-[var(--text-color-secondary)] flex items-center gap-1.5">
				<span class="pulse-dot w-[15px] h-[5px] rounded-full bg-red-500"></span>
				Agora: {{ horaAtual }}
			  </div>
			</div>
		  </div>

		  <!-- Exemplo: badge ou ação -->
		  <span class="text-xs font-semibold text-[var(--text-color-secondary)]">
			<Button icon="pi pi-cog" severity="secondary" outlined class="rounded-full" title="Ver sua Agenda" @click="$router.push('/therapist/agenda')" label="Agenda" />
		  </span>

		</div>
        <div class="mt-2.5 relative">
          <div class="flex justify-between mb-1">
            <div v-for="h in hoursRange" :key="h" class="flex-1 text-left">
              <span class="text-[0.80rem] text-[var(--text-color-secondary)] font-semibold">{{ h }}h</span>
            </div>
          </div>
          <div class="relative h-10 bg-[var(--surface-ground,#f8fafc)] rounded-md overflow-visible">
            <div
              v-for="ev in timelineEvents"
              :key="ev.id"
              class="absolute top-[3px] h-[34px] rounded flex items-center px-1.5 overflow-hidden cursor-default min-w-[32px] hover:brightness-110 transition-[filter] duration-150 z-10"
              :style="{ ...ev.style, ...(ev.bgColor ? { backgroundColor: ev.bgColor, color: ev.txtColor || '#fff' } : {}) }"
              :class="{
                'bg-sky-400':   !ev.bgColor && ev.tipo === 'reuniao',
                'bg-green-500': !ev.bgColor && ev.status === 'realizado',
                'bg-[var(--primary-color,#6366f1)]': !ev.bgColor && ev.tipo !== 'reuniao' && ev.status !== 'realizado',
              }"
              :title="ev.tooltip"
            >
              <span class="text-[0.58rem] font-bold text-white truncate">{{ ev.label }}</span>
              <span v-if="ev.badge" class="text-xs ml-auto">{{ ev.badge }}</span>
            </div>
            <div class="absolute top-0 h-full flex flex-col items-center pointer-events-none z-20" :style="{ left: nowCursorLeft }">
              <div class="w-0.5 h-full bg-red-500 opacity-80" />
              <div class="absolute -top-0.5 w-[7px] h-[7px] rounded-full bg-red-500" />
            </div>
          </div>
        </div>
      </section>

      <!-- Cards de notificação -->
      <section class="grid grid-cols-1 lg:grid-cols-2 gap-3.5">

        <!-- ══ SKELETON dos cards ══════════════════════════════ -->
        <template v-if="loading">
          <div
            v-for="n in 4" :key="n"
            class="flex flex-col bg-[var(--surface-card,#fff)] rounded-md border border-[var(--surface-border,#e2e8f0)]"
          >
            <!-- header -->
            <div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2 border-b border-[var(--surface-border,#f1f5f9)] bg-[var(--surface-ground,#f8fafc)]">
              <Skeleton width="32px" height="32px" border-radius="6px" />
              <div class="flex flex-col gap-1.5 flex-1">
                <Skeleton :width="n % 2 === 0 ? '9rem' : '7rem'" height="12px" />
                <Skeleton :width="n % 3 === 0 ? '13rem' : '10rem'" height="10px" />
              </div>
            </div>
            <!-- body -->
            <div class="flex-1 flex flex-col gap-2 px-3.5 py-3 min-h-[72px]">
              <div v-for="i in 2" :key="i" class="flex items-center gap-2">
                <Skeleton shape="circle" size="26px" />
                <div class="flex flex-col gap-1 flex-1">
                  <Skeleton :width="i === 1 ? '65%' : '50%'" height="10px" />
                  <Skeleton width="75%" height="9px" />
                </div>
              </div>
            </div>
            <!-- footer -->
            <div class="px-3.5 py-2 border-t border-[var(--surface-border,#f1f5f9)]">
              <Skeleton width="5rem" height="10px" />
            </div>
          </div>
          <!-- frase durante carregamento -->
          <div class="lg:col-span-2">
            <AppLoadingPhrases action="Carregando seu dashboard..." containerClass="py-8" />
          </div>
        </template>

        <!-- Agendador Online -->
        <div
          v-if="!loading"
          id="card-agendador"
          class="dash-card rounded-md"
          :class="{ '': solicitacoesPendentes > 0 }"
        >
          <div class="dash-card__head gap-2.5 p-2.5">
            <i class="pi pi-inbox w-10 h-10 rounded-md cfg-subheader__icon" />
            <div>
              <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Agendamentos Recebidos</div>
              <div class="dash-card__sub">Solicitações vindas do agendador online</div>
            </div>
            <span v-if="solicitacoesPendentes > 0" class="dash-card__badge" style="background:color-mix(in srgb,#ef4444 10%,transparent);color:#ef4444;border:1px solid color-mix(in srgb,#ef4444 30%,transparent)">{{ solicitacoesPendentes }}</span>
          </div>

          <div class="dash-card__body">
            <div v-for="sol in solicitacoes" :key="sol.id" class="dash-item bg-[color-mix(in_srgb,var(--surface-ground)_50%,transparent)] p-2 gap-2 rounded-md">
              <Avatar :label="sol.initials" shape="square" size="normal" />
              <div class="min-w-0 flex-1">
                <div class="dash-item__name">{{ sol.nome }}</div>
                <div class="dash-item__sub">{{ sol.detalhe }}</div>
              </div>
              <div class="dash-item__actions">
                <button class="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-green-100 text-green-700 text-sm font-bold hover:bg-green-200 transition-colors" @click="aceitarSol(sol.id)">
                  <i class="pi pi-check text-xs" /> Aceitar
                </button>
                <button class="px-2.5 py-1.5 rounded-full bg-red-50 text-red-500 hover:bg-red-100 transition-colors" @click="recusarSol(sol.id)">
                  <i class="pi pi-times text-xs" />
                </button>
              </div>
            </div>
            <div v-if="!solicitacoes.length" class="dash-empty">
              <i class="pi pi-check-circle" /> Nenhuma solicitação pendente
            </div>
          </div>

          <div class="dash-card__foot" @click="$router.push('/therapist/agendamentos-recebidos')">
            Ver todas →
          </div>
        </div>

        <!-- Cadastros externos -->
        <div v-if="!loading" id="card-cadastros" class="dash-card">
          <div class="dash-card__head gap-2.5 p-2.5">
				<i class="pi pi-user-plus w-10 h-10 rounded-md cfg-subheader__icon" style="background:color-mix(in srgb,#0ea5e9 15%,transparent);color:#0ea5e9" />
            <div>
              <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Cadastros Recebidos (Externos)</div>
              <div class="dash-card__sub">Pacientes que preencheram seus próprios dados</div>
            </div>
            <span v-if="cadastrosPendentes > 0" class="dash-card__badge" style="background:color-mix(in srgb,#0ea5e9 10%,transparent);color:#0ea5e9;border:1px solid color-mix(in srgb,#0ea5e9 30%,transparent)">{{ cadastrosPendentes }}</span>
          </div>

          <div class="dash-card__body">
            <div v-for="c in cadastros" :key="c.id" class="dash-item bg-[color-mix(in_srgb,var(--surface-ground)_50%,transparent)] p-2 gap-2 rounded-md">
              <Avatar :label="c.initials" shape="square" size="normal" />
              <div class="min-w-0 flex-1">
                <div class="dash-item__name">{{ c.nome }}</div>
                <div class="dash-item__sub">{{ c.detalhe }}</div>
              </div>
              <button
                class="w-8 h-8 rounded-full border border-[var(--surface-border)] bg-[var(--surface-ground)] text-[var(--text-color-secondary)] flex items-center justify-center transition-all hover:bg-[var(--primary-color)] hover:text-white hover:border-[var(--primary-color)]"
                @click="$router.push('/therapist/pacientes/triagem/' + c.id)"
              >
                <i class="pi pi-arrow-right text-xs" />
              </button>
            </div>
            <div v-if="!cadastros.length" class="dash-empty">
              <i class="pi pi-check-circle" /> Nenhum cadastro pendente
            </div>
          </div>

          <div class="dash-card__foot" @click="$router.push('/therapist/patients/cadastro/recebidos')">
            Gerenciar triagem →
          </div>
        </div>

        <!-- Recorrências com alerta -->
        <div v-if="!loading" id="card-recorrencias" class="dash-card">
          <div class="dash-card__head gap-2.5 p-2.5">
			<i class="pi pi-refresh w-10 h-10 rounded-md cfg-subheader__icon" style="background:color-mix(in srgb,#f59e0b 15%,transparent);color:#f59e0b" />
            <div>
              <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Recorrências</div>
              <div class="dash-card__sub">Atenção necessária</div>
            </div>
            <span v-if="recAlerta.length" class="dash-card__badge" style="background:color-mix(in srgb,#f59e0b 10%,transparent);color:#f59e0b;border:1px solid color-mix(in srgb,#f59e0b 30%,transparent)">{{ recAlerta.length }}</span>
          </div>

          <div class="dash-card__body">
            <div v-for="r in recAlerta" :key="r.id" class="dash-item bg-[color-mix(in_srgb,var(--surface-ground)_50%,transparent)] p-2 gap-2 rounded-md">
              <div class="min-w-0 flex-1">
                <div class="dash-item__name">{{ r.nome }}</div>
                <div class="dash-item__sub" :class="{ 'text-red-500': r.tipo === 'limite', 'text-amber-500': r.tipo === 'conflito', 'text-sky-500': r.tipo === 'feriado' }">
                  {{ r.motivo }}
                </div>
              </div>
              <div v-if="r.progresso !== undefined" class="flex items-center gap-2 shrink-0">
                <div class="w-14 h-1.5 rounded-full bg-[var(--surface-border)] overflow-hidden">
                  <div class="h-full rounded-full transition-all duration-300" :style="{ width: r.progresso + '%' }" :class="r.progresso > 75 ? 'bg-red-500' : 'bg-[var(--primary-color)]'" />
                </div>
                <span class="text-sm text-[var(--text-color-secondary)] whitespace-nowrap">{{ r.sessoesUsadas }}/{{ r.totalSessoes }}</span>
              </div>
            </div>
            <div v-if="!recAlerta.length" class="dash-empty">
              <i class="pi pi-check-circle" /> Recorrências em dia
            </div>
          </div>

          <div class="dash-card__foot" @click="$router.push('/therapist/agenda/recorrencias')">
            Ver recorrências →
          </div>
        </div>

        <!-- Radar da semana -->
        <div v-if="!loading" id="card-radar" class="dash-card">
          <div class="dash-card__head gap-2.5 p-2.5">
			<i class="pi pi-chart-pie w-10 h-10 rounded-md cfg-subheader__icon" style="background:color-mix(in srgb,#6366f1 15%,transparent);color:#6366f1" />
            <div>
              <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Radar da Semana</div>
              <div class="dash-card__sub">Presença, faltas e reposições</div>
            </div>
          </div>

          <div class="dash-card__body" style="min-height:auto">
            <div class="flex gap-1.5 items-end h-[88px] mt-6">
              <div v-for="d in radarSemana" :key="d.dia" class="flex-1 flex flex-col items-center gap-1">
                <div class="flex-1 w-full flex items-end">
                  <div class="w-full h-[68px] bg-[var(--surface-ground)] rounded overflow-hidden flex items-end">
                    <div
                      class="w-full rounded transition-all duration-500 ease-in-out"
                      :style="{ height: d.pct + '%' }"
                      :class="{
                        'bg-gradient-to-t from-indigo-500 to-indigo-400': d.status === 'ok',
                        'bg-gradient-to-t from-red-500 to-red-300':       d.status === 'falta',
                        'bg-gradient-to-t from-amber-500 to-amber-300':   d.status === 'repo',
                      }"
                    />
                  </div>
                </div>
                <span class="text-sm font-semibold" :class="d.isToday ? 'text-[var(--primary-color)] font-extrabold' : 'text-[var(--text-color-secondary)]'">{{ d.dia }}</span>
                <span class="text-xs text-[var(--text-color-secondary)]">{{ d.total }}</span>
              </div>
            </div>
            <div class="flex gap-3 mt-2 flex-wrap">
              <span class="flex items-center gap-1.5 text-sm text-[var(--text-color-secondary)] font-semibold">
                <span class="w-4 h-2.5 rounded-sm bg-gradient-to-r from-indigo-500 to-indigo-400 flex-shrink-0" />Presentes
              </span>
              <span class="flex items-center gap-1.5 text-sm text-[var(--text-color-secondary)] font-semibold">
                <span class="w-4 h-2.5 rounded-sm bg-gradient-to-r from-red-500 to-red-300 flex-shrink-0" />Faltas
              </span>
              <span class="flex items-center gap-1.5 text-sm text-[var(--text-color-secondary)] font-semibold">
                <span class="w-4 h-2.5 rounded-sm bg-gradient-to-r from-amber-500 to-amber-300 flex-shrink-0" />Reposição
              </span>
            </div>
          </div>
        </div>

      </section>

      <!-- Compromissos especiais -->
      <section v-if="loading" class="bg-[var(--surface-card)] rounded-md border border-[var(--surface-border)] px-[1.125rem] py-3.5">
        <div class="flex items-center justify-between mb-2.5">
          <Skeleton width="10rem" height="12px" />
          <Skeleton width="5rem" height="12px" />
        </div>
        <div class="flex flex-col gap-1.5">
          <div v-for="n in 3" :key="n" class="flex items-center gap-2.5 px-2.5 py-2 rounded-md bg-[var(--surface-ground)]">
            <Skeleton width="3px" height="28px" border-radius="4px" />
            <div class="flex flex-col gap-1 flex-1">
              <Skeleton :width="n === 1 ? '12rem' : n === 2 ? '9rem' : '11rem'" height="11px" />
              <Skeleton width="6rem" height="10px" />
            </div>
            <div class="flex flex-col items-end gap-1">
              <Skeleton width="4rem" height="11px" />
              <Skeleton width="5rem" height="10px" />
            </div>
          </div>
        </div>
      </section>

      <section v-if="!loading" class="bg-[var(--surface-card,#fff)] rounded-md border border-[var(--surface-border,#e2e8f0)] p-2.5">
        <div class="flex items-center justify-between">
          <div class="flex items-center gap-1.5 text-xs font-bold uppercase tracking-[0.06em] text-[var(--text-color-secondary)]">
            <i class="pi pi-briefcase" /> Compromissos especiais (Em breve)
          </div>
			<span
			  v-tooltip.top="{
				value: 'Em breve!',
				showDelay: 0,
				hideDelay: 100
			  }"
			>
			  <button
				class="flex items-center gap-1 bg-transparent border-none cursor-pointer text-xs font-semibold text-[var(--primary-color,#6366f1)] p-0"
				disabled
			  >
				Ver todos <i class="pi pi-arrow-right" />
			  </button>
			</span>
        </div>
        <div class="flex flex-col gap-1.5">
          <div v-for="c in commitments" :key="c.id" class="flex items-center gap-2.5 px-2.5 py-2 rounded-md bg-[var(--surface-ground,#f8fafc)] hover:bg-[var(--surface-hover,#f1f5f9)] transition-colors duration-100">
            <div
              class="w-[3px] h-7 rounded-sm flex-shrink-0"
              :class="{
                'bg-indigo-500': c.cor === 'blue',
                'bg-purple-500': c.cor === 'purple',
                'bg-green-500':  c.cor === 'green',
                'bg-orange-500': c.cor === 'orange',
                'bg-red-500':    c.cor === 'red',
              }"
            />
            <div class="flex-1">
              <span class="block text-xs font-semibold text-[var(--text-color)]">{{ c.titulo }}</span>
              <span class="block text-xs text-[var(--text-color-secondary)]">{{ c.sub }}</span>
            </div>
            <div class="text-right">
              <span class="block text-xs font-semibold text-[var(--text-color)]">{{ c.data }}</span>
              <span
                class="inline-block text-xs font-bold px-1 py-px rounded mt-0.5"
                :class="{
                  'bg-blue-50 text-blue-500':   c.status === 'agendado',
                  'bg-green-50 text-green-600': c.status === 'confirmado',
                  'bg-amber-50 text-amber-600': c.status === 'pendente',
                }"
              >{{ c.statusLabel }}</span>
            </div>
          </div>
        </div>
      </section>

      <LoadedPhraseBlock v-if="!loading" />

    </main>

    <!-- Menus de contexto (fora do aside para evitar visibility:hidden) -->
    <Menu ref="calDayMenuRef" :model="calDayMenuItems" :popup="true" />
    <Menu ref="evMenuRef"     :model="evMenuItems"     :popup="true" />
    <Menu ref="recMenuRef"    :model="recMenuItems"    :popup="true" />

    <!-- Dialog: Novo Compromisso (aberto pelo menu de contexto do mini calendário) -->
    <AgendaEventDialog
      v-if="agendaDialogOpen"
      v-model="agendaDialogOpen"
      :eventRow="agendaDialogEventRow"
      :initialStartISO="agendaDialogStartISO"
      :initialEndISO="agendaDialogEndISO"
      :ownerId="ownerId"
      :tenantId="clinicTenantId"
      :commitmentOptions="commitmentOptionsNormalized"
      newPatientRoute="/therapist/patients/cadastro"
      @save="onAgendaDialogSave"
      @delete="() => { agendaDialogOpen = false; load() }"
    />

    <!-- Dialog: Prontuário do paciente -->
    <PatientProntuario
      :key="selectedPatient?.id || 'none'"
      v-model="prontuarioOpen"
      :patient="selectedPatient"
      @close="closeProntuario"
    />

  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { useRouter } from 'vue-router'
import { useToast } from 'primevue/usetoast'
import Menu from 'primevue/menu'
import { supabase } from '@/lib/supabase/client'
import { useTenantStore } from '@/stores/tenantStore'
import { useAgendaEvents } from '@/features/agenda/composables/useAgendaEvents'
import AgendaEventDialog from '@/features/agenda/components/AgendaEventDialog.vue'
import { useDeterminedCommitments } from '@/features/agenda/composables/useDeterminedCommitments'
import PatientProntuario from '@/features/patients/prontuario/PatientProntuario.vue'

const dashHeroSentinelRef = ref(null)
const heroStuck           = ref(false)
let _heroObserver         = null

const agora     = ref(new Date())
const asideOpen = ref(false)
let timer = null
onBeforeUnmount(() => { clearInterval(timer); _heroObserver?.disconnect() })

const horaAtual = computed(() => {
  const h = agora.value.getHours().toString().padStart(2, '0')
  const m = agora.value.getMinutes().toString().padStart(2, '0')
  return `${h}:${m}`
})

const saudacao = computed(() => {
  const h = agora.value.getHours()
  if (h < 12) return 'Bom dia'
  if (h < 18) return 'Boa tarde'
  return 'Boa noite'
})

const tenantStore = useTenantStore()
const router = useRouter()
const toast  = useToast()
const { create: createEvento, update: updateEvento } = useAgendaEvents()

// ── Prontuário ────────────────────────────────────────────────
const prontuarioOpen  = ref(false)
const selectedPatient = ref(null)

function openProntuario (patientId, patientNome) {
  if (!patientId) return
  selectedPatient.value = { id: patientId, nome_completo: patientNome || '' }
  prontuarioOpen.value  = true
}
function closeProntuario () { prontuarioOpen.value = false; selectedPatient.value = null }

// ── Tipos de compromisso (para o dialog) ─────────────────────
const clinicTenantId = computed(() => tenantStore.activeTenantId || tenantStore.tenantId || null)
const { rows: determinedCommitments, load: loadCommitments } = useDeterminedCommitments(clinicTenantId)

const COMMITMENT_PRIORITY = new Map([
  ['session', 0], ['class', 1], ['study', 2],
  ['reading', 3], ['supervision', 4], ['content_creation', 5],
])

const commitmentOptionsNormalized = computed(() => {
  const list = Array.isArray(determinedCommitments.value) ? determinedCommitments.value : []
  return [...list]
    .filter(i => i?.id && i?.active !== false)
    .sort((a, b) => {
      const pa = COMMITMENT_PRIORITY.get(a.native_key) ?? 99
      const pb = COMMITMENT_PRIORITY.get(b.native_key) ?? 99
      if (pa !== pb) return pa - pb
      return String(a.name || '').localeCompare(String(b.name || ''), 'pt-BR')
    })
    .map(i => ({
      id:          i.id,
      tenant_id:   i.tenant_id   ?? null,
      created_by:  i.created_by  ?? null,
      name:        String(i.name || '').trim() || 'Sem nome',
      description: i.description || '',
      native_key:  i.native_key  || null,
      is_native:   !!i.is_native,
      is_locked:   !!i.is_locked,
      active:      i.active !== false,
      bg_color:    i.bg_color    || null,
      text_color:  i.text_color  || null,
      fields:      Array.isArray(i.determined_commitment_fields)
        ? [...i.determined_commitment_fields].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0))
        : [],
    }))
})

// ── Mini calendário: menu de contexto ────────────────────────
const calDayMenuRef = ref(null)

const calDayMenuItems = computed(() => [
  {
    label: 'Opções do dia',
    items: [
      {
        label: 'Novo Compromisso',
        icon: 'pi pi-plus-circle',
        command: () => openNovoCompromisso(),
      },
      {
        label: 'Ver dia na agenda',
        icon: 'pi pi-calendar',
        command: () => verDiaNaAgenda(),
      },
    ],
  },
])

function onCalDayClick (event, day) {
  selectedDay.value = day
  calDayMenuRef.value?.toggle(event)
}

function verDiaNaAgenda () {
  const d = String(selectedDay.value).padStart(2, '0')
  const m = String(mesAtual + 1).padStart(2, '0')
  router.push(`/therapist/agenda?date=${anoAtual}-${m}-${d}`)
}

// ── Menu de contexto: Eventos do dia ─────────────────────────
const evMenuRef  = ref(null)
const _evAtivo   = ref(null)   // evento clicado

const evMenuItems = computed(() => [
  {
    label: 'Opções',
    items: [
      {
        label: 'Ver prontuário',
        icon: 'pi pi-file-edit',
        disabled: !_evAtivo.value?.patientId,
        command: () => openProntuario(_evAtivo.value?.patientId, _evAtivo.value?.nome),
      },
      {
        label: 'Ver na agenda',
        icon: 'pi pi-calendar',
        command: () => {
          if (!_evAtivo.value?.inicioISO) return
          const d = new Date(_evAtivo.value.inicioISO)
          const ds = d.toISOString().slice(0, 10)
          router.push(`/therapist/agenda?date=${ds}`)
        },
      },
    ],
  },
])

function openEvMenu (event, ev) {
  _evAtivo.value = ev
  evMenuRef.value?.toggle(event)
}

// ── Menu de contexto: Recorrências ativas ────────────────────
const recMenuRef = ref(null)
const _recAtivo  = ref(null)   // recorrência clicada

const recMenuItems = computed(() => [
  {
    label: 'Opções',
    items: [
      {
        label: 'Ver prontuário',
        icon: 'pi pi-file-edit',
        disabled: !_recAtivo.value?.patientId,
        command: () => openProntuario(_recAtivo.value?.patientId, _recAtivo.value?.nome),
      },
      {
        label: 'Ver na agenda',
        icon: 'pi pi-calendar',
        command: () => router.push('/therapist/agenda'),
      },
    ],
  },
])

function openRecMenu (event, r) {
  _recAtivo.value = r
  recMenuRef.value?.toggle(event)
}

// ── Dialog: Novo Compromisso ──────────────────────────────────
const agendaDialogOpen     = ref(false)
const agendaDialogEventRow = ref(null)
const agendaDialogStartISO = ref('')
const agendaDialogEndISO   = ref('')

function openNovoCompromisso () {
  if (!ownerId.value) return
  const durMin = 50
  const now    = new Date()
  const base   = new Date(anoAtual, mesAtual, selectedDay.value, now.getHours(), now.getMinutes(), 0, 0)

  agendaDialogEventRow.value = {
    owner_id:   ownerId.value,
    tipo:       'sessao',
    status:     'agendado',
    titulo:     null,
    observacoes: null,
  }
  agendaDialogStartISO.value = base.toISOString()
  agendaDialogEndISO.value   = new Date(base.getTime() + durMin * 60000).toISOString()
  agendaDialogOpen.value     = true
}

function _isUuid (v) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(String(v || ''))
}

function _pickDbFields (obj) {
  const allowed = [
    'tenant_id', 'owner_id', 'terapeuta_id', 'patient_id',
    'tipo', 'status', 'titulo', 'observacoes',
    'inicio_em', 'fim_em', 'visibility_scope',
    'determined_commitment_id', 'titulo_custom', 'extra_fields',
    'recurrence_id', 'recurrence_date',
    'price', 'insurance_plan_id', 'insurance_guide_number',
    'insurance_value', 'insurance_plan_service_id',
  ]
  const out = {}
  for (const k of allowed) { if (obj[k] !== undefined) out[k] = obj[k] }
  return out
}

async function onAgendaDialogSave (arg) {
  try {
    const isWrapped = !!arg && typeof arg === 'object' && Object.prototype.hasOwnProperty.call(arg, 'payload')
    const payload   = isWrapped ? arg.payload : arg
    const id        = isWrapped ? (arg.id ?? null) : (arg?.id ?? null)

    const normalized = { ...(payload || {}) }

    if (!normalized.owner_id && ownerId.value) normalized.owner_id = ownerId.value

    const tid = clinicTenantId.value
    if (!tid) throw new Error('tenant_id não encontrado.')
    normalized.tenant_id = tid

    if (!normalized.visibility_scope) normalized.visibility_scope = 'public'
    if (!normalized.status) normalized.status = 'agendado'
    if (!normalized.tipo)   normalized.tipo   = 'sessao'
    if (!String(normalized.titulo || '').trim()) normalized.titulo = normalized.tipo === 'bloqueio' ? 'Ocupado' : 'Sessão'
    if (!_isUuid(normalized.paciente_id)) normalized.paciente_id = null
    if (normalized.determined_commitment_id && !_isUuid(normalized.determined_commitment_id)) normalized.determined_commitment_id = null

    const dbPayload = _pickDbFields(normalized)

    if (id) {
      await updateEvento(id, dbPayload)
      toast.add({ severity: 'success', summary: 'Salvo', detail: 'Compromisso atualizado.', life: 2500 })
    } else {
      await createEvento(dbPayload)
      toast.add({ severity: 'success', summary: 'Criado', detail: 'Compromisso criado com sucesso.', life: 2500 })
    }

    agendaDialogOpen.value = false
    await load()

  } catch (e) {
    const msg = String(e?.message || '')
    const isOverlap =
      e?.code === '23P01' ||
      msg.includes('agenda_eventos_sem_sobreposicao') ||
      msg.includes('exclusion constraint')
    if (isOverlap) {
      toast.add({ severity: 'warn', summary: 'Conflito de horário', detail: 'Já existe um compromisso neste horário.', life: 4000 })
    } else {
      toast.add({ severity: 'error', summary: 'Erro ao salvar', detail: msg || 'Tente novamente.', life: 4000 })
    }
  }
}

const loading            = ref(true)
const ownerId            = ref(null)
const eventosDoMes       = ref([])
const regraRecorrencias  = ref([])
const _solicitacoesBruto = ref([])
const _cadastrosBruto    = ref([])

const diasSemana  = ['D', 'S', 'T', 'Q', 'Q', 'S', 'S']
const hoje        = agora.value.getDate()
const mesAtual    = agora.value.getMonth()
const anoAtual    = agora.value.getFullYear()
const selectedDay = ref(hoje)

const eventMap = computed(() => {
  const map = {}
  for (const ev of eventosDoMes.value) {
    if (!ev.inicio_em) continue
    const d = new Date(ev.inicio_em)
    if (d.getMonth() !== mesAtual || d.getFullYear() !== anoAtual) continue
    const day = d.getDate()
    if (!map[day]) map[day] = { count: 0, hasEvent: true }
    map[day].count++
  }
  for (const day in map) {
    const c = map[day].count
    map[day].urgency = c >= 5 ? 'urg-alta' : c >= 3 ? 'urg-media' : 'urg-baixa'
  }
  return map
})

const calCells = computed(() => {
  const primeiroDia = new Date(anoAtual, mesAtual, 1).getDay()
  const totalDias   = new Date(anoAtual, mesAtual + 1, 0).getDate()
  const cells = []
  for (let i = 0; i < primeiroDia; i++)
    cells.push({ key: 'e' + i, day: null, isOther: true, isToday: false, hasEvent: false, count: 0, urgency: '' })
  for (let d = 1; d <= totalDias; d++) {
    const ev = eventMap.value[d] || {}
    cells.push({ key: 'd' + d, day: d, isToday: d === hoje, isOther: false, hasEvent: !!ev.hasEvent, count: ev.count || 0, urgency: ev.urgency || '' })
  }
  return cells
})

const labelDiaSelecionado = computed(() => {
  if (selectedDay.value === hoje) return 'Hoje'
  if (selectedDay.value === hoje + 1) return 'Amanhã'
  return `Dia ${selectedDay.value}/${String(mesAtual + 1).padStart(2, '0')}`
})

const STATUS_ICON = {
  realizado: 'pi pi-check-circle',
  faltou:    'pi pi-times-circle',
  cancelado: 'pi pi-times-circle',
  remarcar:  'pi pi-undo',
  agendado:  'pi pi-clock',
}

const commitmentColorMap = computed(() =>
  new Map(
    commitmentOptionsNormalized.value
      .filter(c => c.id && c.bg_color)
      .map(c => [c.id, { bg_color: c.bg_color, text_color: c.text_color }])
  )
)

function buildEventoItem (ev) {
  const inicio = new Date(ev.inicio_em)
  const fim    = ev.fim_em ? new Date(ev.fim_em) : null
  const durMin = fim ? Math.round((fim - inicio) / 60000) : 50
  const h = inicio.getHours().toString().padStart(2, '0')
  const m = inicio.getMinutes().toString().padStart(2, '0')
  const joinColor = ev.determined_commitments
  const mapColor  = ev.determined_commitment_id ? commitmentColorMap.value.get(ev.determined_commitment_id) : null
  const bgColor   = joinColor?.bg_color   ? `#${joinColor.bg_color}`   : mapColor?.bg_color   ? `#${mapColor.bg_color}`   : null
  const txtColor  = joinColor?.text_color ? `#${joinColor.text_color}` : mapColor?.text_color ? `#${mapColor.text_color}` : null
  return {
    id: ev.id, hora: `${h}:${m}`, dur: `${durMin}min`,
    nome: ev.patients?.nome_completo || ev.titulo || ev.titulo_custom || '—',
    modalidade: ev.modalidade || 'Presencial', recorrente: !!ev.recurrence_id,
    status: ev.status || 'agendado', statusIcon: STATUS_ICON[ev.status] || 'pi pi-clock',
    tipo: ev.tipo || 'sessao',
    patientId: ev.patient_id || null,
    inicioISO: ev.inicio_em || null,
    bgColor, txtColor,
  }
}

const eventosDoDia = computed(() =>
  eventosDoMes.value
    .filter(ev => {
      if (!ev.inicio_em) return false
      const d = new Date(ev.inicio_em)
      return d.getDate() === selectedDay.value && d.getMonth() === mesAtual && d.getFullYear() === anoAtual
    })
    .sort((a, b) => new Date(a.inicio_em) - new Date(b.inicio_em))
    .map(buildEventoItem)
)

const FREQ_LABEL = { weekly: 'Semanal', biweekly: 'Quinzenal', monthly: 'Mensal', custom_weekdays: 'Personalizado' }
const DIAS_PT    = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb']

function initials (nome) {
  const parts = (nome || '').trim().split(/\s+/)
  if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase()
  return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()
}

function hashColor (str) {
  const palette = ['#6366f1','#0ea5e9','#ec4899','#f59e0b','#22c55e','#8b5cf6','#ef4444','#14b8a6']
  let h = 0
  for (let i = 0; i < (str || '').length; i++) h = (h * 31 + str.charCodeAt(i)) & 0xffffffff
  return palette[Math.abs(h) % palette.length]
}

function nextOccurrenceLabel (rule) {
  const todayDow = new Date().getDay()
  const weekdays = Array.isArray(rule.weekdays) ? rule.weekdays : []
  if (!weekdays.length) return '—'
  if (rule.type === 'weekly' || rule.type === 'custom_weekdays') {
    if (weekdays.includes(todayDow)) return 'Hoje'
    let minDiff = 8
    for (const w of weekdays) { let diff = w - todayDow; if (diff <= 0) diff += 7; if (diff < minDiff) minDiff = diff }
    if (minDiff === 1) return 'Amanhã'
    if (minDiff < 8) return `Em ${minDiff} dias`
  }
  if (rule.type === 'biweekly') {
    if (weekdays.includes(todayDow)) return 'Hoje'
    if (weekdays.includes((todayDow + 1) % 7)) return 'Amanhã'
  }
  return '—'
}

const recorrencias = computed(() =>
  regraRecorrencias.value.slice(0, 8).map(r => {
    const nome    = r._patientNome || '—'
    const parts   = nome.split(' ')
    const nomeAb  = parts[0] + (parts[1] ? ' ' + parts[1][0] + '.' : '')
    const freq    = FREQ_LABEL[r.type] || r.type || '—'
    const weekdays = Array.isArray(r.weekdays) ? r.weekdays : []
    const diaLabel = weekdays.map(d => DIAS_PT[d]).join(', ')
    const hora    = r.start_time ? String(r.start_time).slice(0, 5) : ''
    const proxLabel = nextOccurrenceLabel(r)
    return { id: r.id, nome: nomeAb, freq: `${freq} · ${diaLabel}${hora ? ' ' + hora : ''}`, proxLabel, proxHoje: proxLabel === 'Hoje', color: hashColor(r.patient_id || r.id), initials: initials(nome), patientId: r.patient_id || null }
  })
)

// ── Derivados de eventosDoMes — single pass ───────────────────
// Um único computed varre o array uma vez e extrai tudo,
// evitando N loops separados que re-executam a cada reatividade.
const _statsDoMes = computed(() => {
  const now      = agora.value
  const semIni   = new Date(now); semIni.setDate(now.getDate() - now.getDay()); semIni.setHours(0, 0, 0, 0)
  const semFim   = new Date(semIni); semFim.setDate(semIni.getDate() + 6); semFim.setHours(23, 59, 59, 999)
  const daqui30  = new Date(now); daqui30.setDate(now.getDate() + 30)

  let hojeCnt = 0, semanaCnt = 0, realizadosCnt = 0, encerradosCnt = 0
  const hojeLista = [], timelineLista = []
  const diasSemanaMap = [[], [], [], [], [], [], []]

  for (const ev of eventosDoMes.value) {
    if (!ev.inicio_em) continue
    const d = new Date(ev.inicio_em)
    const dDay = d.getDate(), dMon = d.getMonth(), dYear = d.getFullYear()
    const isHoje = dDay === hoje && dMon === mesAtual && dYear === anoAtual

    if (isHoje) { hojeCnt++; hojeLista.push(ev); timelineLista.push(ev) }
    if (d >= semIni && d <= semFim) {
      semanaCnt++
      diasSemanaMap[d.getDay()].push(ev)
    }
    if (d < now && ['realizado','faltou','cancelado'].includes(ev.status)) {
      encerradosCnt++
      if (ev.status === 'realizado') realizadosCnt++
    }
  }

  const taxaPresenca = encerradosCnt > 0 ? Math.round((realizadosCnt / encerradosCnt) * 100) : null

  return { hojeCnt, semanaCnt, taxaPresenca, hojeLista, timelineLista, diasSemanaMap }
})

const eventosHoje   = computed(() => _statsDoMes.value.hojeLista)
const eventosSemana = computed(() => ({ length: _statsDoMes.value.semanaCnt }))
const taxaPresenca  = computed(() => _statsDoMes.value.taxaPresenca)

const quickStats = computed(() => {
  const pendentes = _solicitacoesBruto.value.length + _cadastrosBruto.value.length
  const pct = taxaPresenca.value
  return [
    { value: String(_statsDoMes.value.hojeCnt),    label: 'Hoje',      cls: '' },
    { value: String(pendentes),                     label: 'Pendentes', cls: pendentes > 0 ? 'qs-urgente' : '' },
    { value: String(_statsDoMes.value.semanaCnt),   label: 'Semana',    cls: '' },
    { value: pct !== null ? `${pct}%` : '—',       label: 'Presença',  cls: pct !== null && pct >= 85 ? 'qs-ok' : '' },
  ]
})

const resumoHoje = computed(() => {
  const sessoes = _statsDoMes.value.hojeLista.filter(ev => ev.tipo !== 'bloqueio').length
  const sols    = _solicitacoesBruto.value.length
  const parts = []
  if (sessoes === 1) parts.push('1 sessão hoje')
  else if (sessoes > 1) parts.push(`${sessoes} sessões hoje`)
  else parts.push('Nenhuma sessão hoje')
  if (sols > 0) parts.push(`${sols} solicitaç${sols === 1 ? 'ão' : 'ões'} aguarda${sols === 1 ? '' : 'm'} sua atenção`)
  return parts.join(' · ')
})

const solicitacoes = computed(() =>
  _solicitacoesBruto.value.map(s => {
    const nome  = `${s.paciente_nome || ''} ${s.paciente_sobrenome || ''}`.trim() || '—'
    const dia   = s.data_solicitada ? new Date(s.data_solicitada + 'T00:00:00').toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' }) : '—'
    const hora  = s.hora_solicitada ? String(s.hora_solicitada).slice(0, 5) : ''
    const tipo  = s.tipo === 'primeira' ? 'Primeira consulta' : s.tipo === 'retorno' ? 'Retorno' : s.tipo || '—'
    const modal = s.modalidade === 'online' ? 'Online' : s.modalidade === 'presencial' ? 'Presencial' : s.modalidade || '—'
    return { id: s.id, nome, initials: initials(nome), detalhe: `${tipo} · ${modal} · ${dia}${hora ? ' ' + hora : ''}` }
  })
)
const solicitacoesPendentes = computed(() => solicitacoes.value.length)

async function aceitarSol (id) {
  try { await supabase.from('agendador_solicitacoes').update({ status: 'autorizado' }).eq('id', id); _solicitacoesBruto.value = _solicitacoesBruto.value.filter(s => s.id !== id) } catch (e) { console.error('[TherapistDashboard] aceitarSol:', e) }
}
async function recusarSol (id) {
  try { await supabase.from('agendador_solicitacoes').update({ status: 'recusado' }).eq('id', id); _solicitacoesBruto.value = _solicitacoesBruto.value.filter(s => s.id !== id) } catch (e) { console.error('[TherapistDashboard] recusarSol:', e) }
}

const cadastros = computed(() =>
  _cadastrosBruto.value.map(c => {
    const nome   = c.nome_completo || '—'
    const criado = c.created_at ? new Date(c.created_at).toLocaleDateString('pt-BR') : '—'
    return { id: c.id, nome, initials: initials(nome), detalhe: `Via portal · ${criado}` }
  })
)
const cadastrosPendentes = computed(() => cadastros.value.length)

const recAlerta = computed(() => {
  const now = new Date(), daqui30 = new Date(); daqui30.setDate(now.getDate() + 30)
  const alerts = []
  for (const r of regraRecorrencias.value) {
    const nome = (r._patientNome || '—').split(' ').slice(0, 2).join(' ')
    if (r.end_date) { const ed = new Date(r.end_date + 'T00:00:00'); if (ed >= now && ed <= daqui30) alerts.push({ id: r.id + '_end', nome, motivo: 'Encerramento próximo', tipo: 'feriado' }) }
    if (r.max_occurrences && r._sessionsCount !== undefined) {
      const pct = (r._sessionsCount / r.max_occurrences) * 100
      if (pct > 75) alerts.push({ id: r.id + '_limit', nome, motivo: 'Limite próximo', tipo: 'limite', sessoesUsadas: r._sessionsCount, totalSessoes: r.max_occurrences, progresso: Math.round(pct) })
    }
  }
  return alerts.slice(0, 5)
})

const radarSemana = computed(() => {
  const diasMap = _statsDoMes.value.diasSemanaMap
  const dow = agora.value.getDay()
  return DIAS_PT.map((dia, i) => {
    const evs = diasMap[i]
    const total = evs.length
    const presentes  = evs.filter(ev => ev.status === 'realizado').length
    const faltas     = evs.filter(ev => ev.status === 'faltou').length
    const reposicao  = evs.filter(ev => ['reposicao','reposição'].includes(ev.status)).length
    let status = 'ok'
    if (faltas > 0 && faltas >= presentes) status = 'falta'
    else if (reposicao > 0 && reposicao > presentes) status = 'repo'
    return { dia, total, pct: total === 0 ? 0 : Math.min(Math.round((total / 6) * 100), 100), status, isToday: i === dow }
  })
})

const CHIP_CORES = ['blue', 'purple', 'green', 'orange', 'red']
const STATUS_LABEL_MAP = { agendado: 'Agendado', confirmado: 'Confirmado', cancelado: 'Cancelado', realizado: 'Realizado', pendente: 'Pendente' }

const commitments = computed(() => {
  const now = new Date()
  return eventosDoMes.value
    .filter(ev => ev.tipo === 'bloqueio' && ev.inicio_em && new Date(ev.inicio_em) >= now && (ev.titulo || ev.titulo_custom))
    .sort((a, b) => new Date(a.inicio_em) - new Date(b.inicio_em))
    .slice(0, 5)
    .map((ev, i) => { const d = new Date(ev.inicio_em); return { id: ev.id, titulo: ev.titulo || ev.titulo_custom, sub: ev.modalidade || '—', data: d.toLocaleDateString('pt-BR'), cor: CHIP_CORES[i % CHIP_CORES.length], status: ev.status || 'agendado', statusLabel: STATUS_LABEL_MAP[ev.status] || 'Agendado' } })
})

const hoursRange = [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
const TL_START = 7, TL_END = 20, TL_SPAN = TL_END - TL_START
function toPercent (h, m) { return ((h + m / 60 - TL_START) / TL_SPAN) * 100 }


const timelineEvents = computed(() =>
  _statsDoMes.value.timelineLista
    .slice()
    .sort((a, b) => new Date(a.inicio_em) - new Date(b.inicio_em))
    .map(ev => {
      const item = buildEventoItem(ev)
      const [hh, mm] = item.hora.split(':').map(Number)
      const durMin = parseInt(item.dur) || 50
      return { id: item.id, label: item.nome.split(' ')[0], tipo: item.tipo, status: item.status, tooltip: `${item.hora} · ${item.nome} · ${item.modalidade}`, badge: item.modalidade?.toLowerCase() === 'online' ? '📱' : '', bgColor: item.bgColor, txtColor: item.txtColor, style: { left: toPercent(hh, mm) + '%', width: Math.max((durMin / 60 / TL_SPAN) * 100, 4) + '%' } }
    })
)

const nowCursorLeft = computed(() => {
  const pct = toPercent(agora.value.getHours(), agora.value.getMinutes())
  return Math.min(Math.max(pct, 0), 100) + '%'
})

async function load () {
  loading.value = true
  const { data: authData } = await supabase.auth.getUser()
  ownerId.value = authData?.user?.id || null
  if (!ownerId.value) { loading.value = false; return }
  await tenantStore.ensureLoaded()
  const tid = tenantStore.activeTenantId || tenantStore.tenantId || null
  await loadCommitments()
  const mesInicio = new Date(anoAtual, mesAtual, 1, 0, 0, 0, 0).toISOString()
  const mesFim    = new Date(anoAtual, mesAtual + 1, 0, 23, 59, 59, 999).toISOString()
  try {
    const [eventosRes, recRes, solRes, cadRes] = await Promise.all([
      (() => { let q = supabase.from('agenda_eventos').select('id, inicio_em, fim_em, status, modalidade, tipo, titulo, titulo_custom, patient_id, recurrence_id, determined_commitment_id, patients(nome_completo), determined_commitments(bg_color, text_color)').eq('owner_id', ownerId.value).gte('inicio_em', mesInicio).lte('inicio_em', mesFim).order('inicio_em', { ascending: true }); if (tid) q = q.eq('tenant_id', tid); return q })(),
      (() => { let q = supabase.from('recurrence_rules').select('id, patient_id, type, interval, weekdays, start_date, end_date, max_occurrences, start_time').eq('owner_id', ownerId.value).eq('status', 'ativo').order('start_date', { ascending: false }); if (tid) q = q.eq('tenant_id', tid); return q })(),
      supabase.from('agendador_solicitacoes').select('id, paciente_nome, paciente_sobrenome, tipo, modalidade, data_solicitada, hora_solicitada').eq('owner_id', ownerId.value).eq('status', 'pendente').order('created_at', { ascending: false }).limit(10),
      supabase.from('patient_intake_requests').select('id, nome_completo, status, created_at').eq('owner_id', ownerId.value).eq('status', 'new').order('created_at', { ascending: false }).limit(10),
    ])
    eventosDoMes.value = eventosRes.data || []; _solicitacoesBruto.value = solRes.data || []; _cadastrosBruto.value = cadRes.data || []
    const rawRules = recRes.data || []
    const patientIds = [...new Set(rawRules.map(r => r.patient_id).filter(Boolean))]
    if (patientIds.length) {
      const { data: pts } = await supabase.from('patients').select('id, nome_completo').in('id', patientIds)
      const ptMap = Object.fromEntries((pts || []).map(p => [p.id, p.nome_completo]))
      for (const r of rawRules) r._patientNome = ptMap[r.patient_id] || '—'
    } else { for (const r of rawRules) r._patientNome = '—' }
    const rulesComLimite = rawRules.filter(r => r.max_occurrences)
    if (rulesComLimite.length) {
      const { data: sessData } = await supabase.from('agenda_eventos').select('id, recurrence_id').in('recurrence_id', rulesComLimite.map(r => r.id)).in('status', ['agendado','realizado'])
      const countMap = {}
      for (const s of sessData || []) { if (s.recurrence_id) countMap[s.recurrence_id] = (countMap[s.recurrence_id] || 0) + 1 }
      for (const r of rawRules) r._sessionsCount = countMap[r.id] || 0
    }
    regraRecorrencias.value = rawRules
  } catch (e) { console.error('[TherapistDashboard] load:', e) }
  finally { loading.value = false }
}

onMounted(async () => {
  timer = setInterval(() => { agora.value = new Date() }, 60000)
  _heroObserver = new IntersectionObserver(([entry]) => { heroStuck.value = !entry.isIntersecting }, { threshold: 0 })
  if (dashHeroSentinelRef.value) _heroObserver.observe(dashHeroSentinelRef.value)
  await load()
})
</script>

<style scoped>
/* Aside drawer — transição e comportamento responsivo não cobertos por Tailwind base */
.aside-drawer {
  position: fixed;
  top: 0; left: 0;
  height: 100dvh;
  width: min(300px, 85vw);
  z-index: 40;
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), visibility 0.25s;
  box-shadow: 4px 0 24px rgba(0,0,0,0.15);
}
@media (min-width: 1280px) {
  .aside-drawer {
    position: sticky;
    top: 0;
    height: calc(100vh - 4.5rem);
    width: 272px;
    transform: none;
    visibility: visible;
    box-shadow: none;
    z-index: auto;
  }
}

/* Pulse dot — animação não disponível sem JIT */
.pulse-dot { animation: pulse-red 1.5s infinite; }
@keyframes pulse-red {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0.4); }
  50%       { box-shadow: 0 0 0 4px rgba(239,68,68,0); }
}


/* ── Aside: Eventos do dia ───────────────────────── */
.aside-ev {
  display: flex; align-items: center; gap: 0.625rem;
  padding: 0.5rem 0.625rem;
  border-radius: 8px;
  border-left: 3px solid var(--ev-color, var(--primary-color, #6366f1));
  background: var(--surface-ground, #f8fafc);
  cursor: pointer;
  transition: background 0.12s, box-shadow 0.12s;
}
.aside-ev:hover { background: var(--surface-hover, #f1f5f9); box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
.aside-ev--reuniao   { --ev-color: #38bdf8; }
.aside-ev--realizado { --ev-color: #22c55e; }
.aside-ev--default   { --ev-color: var(--primary-color, #6366f1); }
.aside-ev--skeleton  { cursor: default; pointer-events: none; }

.aside-ev__time {
  display: flex; flex-direction: column; align-items: flex-end;
  min-width: 36px; flex-shrink: 0; gap: 1px;
}
.aside-ev__hora {
  font-size: 0.78rem; font-weight: 800; color: var(--text-color);
  letter-spacing: -0.01em; line-height: 1;
}
.aside-ev__dur {
  font-size: 0.68rem; color: var(--text-color-secondary); line-height: 1;
}
.aside-ev__badge {
  font-size: 0.68rem; font-weight: 600; padding: 1px 6px;
  border-radius: 4px; background: var(--surface-border, #e2e8f0);
  color: var(--text-color-secondary); line-height: 1.5; white-space: nowrap;
}

/* ── Aside: Recorrências ativas ──────────────────── */
.aside-rec {
  display: flex; align-items: center; gap: 0.625rem;
  padding: 0.45rem 0.5rem;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.aside-rec:hover {
  background: var(--surface-ground, #f8fafc);
  border-color: var(--surface-border, #e2e8f0);
}
.aside-rec--skeleton { cursor: default; pointer-events: none; }
.aside-rec__prox {
  font-size: 0.72rem; white-space: nowrap; flex-shrink: 0;
  padding: 2px 7px; border-radius: 999px;
  background: color-mix(in srgb, currentColor 10%, transparent);
}
</style>