<script setup>
/*
 * MelissaCronometro
 * --------------------------------------------------
 * Cronômetro de sessão estilo "janela do Windows":
 *   - Dialog centralizado com select de paciente, display gigante e ações
 *   - Click fora minimiza (chip no canto superior esquerdo)
 *   - X/ESC fecha (destrói)
 *   - Botão inferior alterna entre "▶ Começar" e "⏹ Parar"
 *   - "+1 minuto" estende o tempo
 *   - Quando minimizado, o timer continua rodando em background
 *
 * Uso:
 *   <MelissaCronometro
 *       ref="cronoRef"
 *       :pacientes="lista"
 *       default-paciente-id="p1"
 *       :duracao-minutos="50"
 *       @visible-change="cronoVisivel = $event"
 *   />
 *
 *   cronoRef.value.abrir()   // abre / restaura
 *   cronoRef.value.fechar()  // destrói
 */
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue';
import { playToque } from './melissaToques';

const STORAGE_KEY = 'melissa.cronometro.v1';

const props = defineProps({
    pacientes: {
        type: Array,
        default: () => []
        // Cada item: { id: string, nome: string }
    },
    defaultPacienteId: {
        type: [String, Number, null],
        default: null
    },
    duracaoMinutos: {
        type: Number,
        default: 50
    },
    toqueTermino: {
        type: String,
        default: 'sino'
    }
});

const emit = defineEmits(['visible-change', 'close', 'complete']);

// ── Estado interno ─────────────────────────────────────────────
const exists = ref(false);
const minimized = ref(false);
const running = ref(false);
const seconds = ref(props.duracaoMinutos * 60);
const pacienteId = ref(props.defaultPacienteId);
let timer = null;

// True só durante a transição de minimizar (dialog → chip).
// Permite trocar a animação leave do dialog por "shrink + fly to dock"
// (tipo macOS minimize) em vez do lift normal usado pra fechar.
const isMinimizing = ref(false);

// ── Computeds ──────────────────────────────────────────────────
const visible = computed(() => exists.value && !minimized.value);

const dialogTransitionName = computed(() => (isMinimizing.value ? 'minimize' : 'lift'));

const display = computed(() => {
    const total = seconds.value;
    const sign = total < 0 ? '-' : '';
    const abs = Math.abs(total);
    const m = Math.floor(abs / 60);
    const s = abs % 60;
    return `${sign}${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
});

const excedido = computed(() => seconds.value < 0);

const status = computed(() => {
    if (running.value) return 'Em andamento';
    if (seconds.value === props.duracaoMinutos * 60) return 'Pronto';
    return 'Pausado';
});

const pacienteNome = computed(() => {
    if (!pacienteId.value) return 'Atividade livre';
    const p = props.pacientes.find((x) => x.id === pacienteId.value);
    return p ? p.nome : '';
});

// ── Watch: avisa parent quando dialog aparece/some ─────────────
watch(visible, (v) => emit('visible-change', v));

// ── Ações ──────────────────────────────────────────────────────
function abrir() {
    if (exists.value) {
        // Já existe — apenas restaura se tava minimizado (não cria outro)
        if (minimized.value) minimized.value = false;
        return;
    }
    seconds.value = props.duracaoMinutos * 60;
    pacienteId.value = props.defaultPacienteId;
    running.value = false;
    minimized.value = false;
    exists.value = true;
}

function toggle() {
    if (running.value) {
        if (timer) clearInterval(timer);
        timer = null;
        running.value = false;
        // Zera ao parar — sessão acabou, deixa pronto pra próxima
        seconds.value = props.duracaoMinutos * 60;
    } else {
        if (timer) clearInterval(timer);
        timer = setInterval(() => {
            const wasPositive = seconds.value > 0;
            seconds.value -= 1;
            // Toca exatamente na transição positivo → zero/negativo (uma única vez)
            if (wasPositive && seconds.value <= 0) {
                playToque(props.toqueTermino);
            }
        }, 1000);
        running.value = true;
    }
}

function minimizar() {
    isMinimizing.value = true;
    minimized.value = true;
    // Reset do flag depois da animação completar (340ms + buffer)
    setTimeout(() => { isMinimizing.value = false; }, 380);
}

function restaurar() {
    minimized.value = false;
}

function fechar() {
    if (timer) clearInterval(timer);
    timer = null;
    running.value = false;
    minimized.value = false;
    exists.value = false;
    emit('close');
}

function ajustarMinutos(delta) {
    seconds.value += delta * 60;
    // Re-baselina savedAt pra restore após reload pegar o novo valor correto
    saveState();
}

// ── Persistência (localStorage) ────────────────────────────────
// Snapshot inclui timestamp pra calcular elapsed real no restore —
// caso o usuário recarregue/feche a aba enquanto o timer roda, ao
// voltar o seconds reflete o tempo real (a sessão acontece na sala,
// não na aba).
function saveState() {
    if (!exists.value) {
        try { localStorage.removeItem(STORAGE_KEY); } catch {}
        return;
    }
    const snap = {
        pacienteId: pacienteId.value,
        minimized: !!minimized.value,
        running: !!running.value,
        seconds: seconds.value,
        savedAt: Date.now()
    };
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify(snap)); } catch {}
}

function loadState() {
    let raw;
    try { raw = localStorage.getItem(STORAGE_KEY); } catch { return false; }
    if (!raw) return false;

    let snap;
    try { snap = JSON.parse(raw); } catch { return false; }
    if (!snap || typeof snap !== 'object') return false;

    // Sanitização: cada campo do storage é input externo, não confiar
    const validIds = new Set(props.pacientes.map((p) => p.id));
    const pid = snap.pacienteId === null || validIds.has(snap.pacienteId)
        ? snap.pacienteId
        : props.defaultPacienteId;

    const savedSeconds = Number(snap.seconds);
    if (!Number.isFinite(savedSeconds)) return false;

    const savedAt = Number(snap.savedAt);
    const wasRunning = !!snap.running;

    // Se rodava, desconta tempo real desde o save (limite 24h pra evitar abuso de relógio)
    let restoredSeconds = savedSeconds;
    if (wasRunning && Number.isFinite(savedAt)) {
        const elapsed = Math.max(0, Math.min(86400, Math.floor((Date.now() - savedAt) / 1000)));
        restoredSeconds = savedSeconds - elapsed;
    }

    pacienteId.value = pid;
    minimized.value = !!snap.minimized;
    seconds.value = restoredSeconds;
    exists.value = true;
    running.value = false; // toggle abaixo flipa pra true

    if (wasRunning) {
        // Retoma o interval. NÃO toca o toque retroativo — se o tempo
        // já está negativo no restore, foi "perdido" durante o reload.
        toggle();
    }
    return true;
}

// Watch nas mudanças de estado discreto (não em seconds enquanto roda — savedAt+delta dá conta)
watch([exists, minimized, running, pacienteId], () => saveState());

// ── Mount / Cleanup ────────────────────────────────────────────
onMounted(() => {
    loadState();
});

onBeforeUnmount(() => {
    if (timer) clearInterval(timer);
});

defineExpose({ abrir, fechar, minimizar, restaurar, toggle, visible });
</script>

<template>
    <!-- Dialog centralizado.
         Transition name dinâmico: 'minimize' quando user minimiza (anima
         shrink + fly em direção ao dock no bottom-left), 'lift' default
         pros outros casos (fechar, abrir). -->
    <Transition :name="dialogTransitionName">
        <div v-if="visible" class="mc-layer" @click.self="minimizar">
            <div class="mc-panel">
                <div class="flex items-center justify-between mb-5">
                    <div>
                        <div class="text-white/55 text-xs uppercase tracking-[0.2em]">Cronômetro</div>
                        <div class="text-white text-lg font-light mt-1">{{ status }}</div>
                    </div>
                    <div class="flex items-center gap-1.5">
                        <button class="mc-glass-btn" title="Minimizar" @click="minimizar">
                            <i class="pi pi-window-minimize text-white/90 text-xs" />
                        </button>
                        <button class="mc-glass-btn" title="Fechar" @click="fechar">
                            <i class="pi pi-times text-white/90 text-sm" />
                        </button>
                    </div>
                </div>

                <!-- Select de paciente / atividade -->
                <div class="mb-6">
                    <label class="text-[0.65rem] uppercase tracking-widest text-white/50 mb-2 block">
                        Paciente / atividade
                    </label>
                    <div class="relative">
                        <select v-model="pacienteId" class="mc-select">
                            <option :value="null">— Atividade livre (sem paciente)</option>
                            <option v-for="p in pacientes" :key="p.id" :value="p.id">
                                {{ p.nome }}
                            </option>
                        </select>
                        <i class="pi pi-chevron-down mc-select-icon" />
                    </div>
                </div>

                <!-- Display gigante + steppers manuais (+5 / -5) -->
                <div class="mb-7">
                    <div class="flex items-center justify-center gap-4">
                        <div class="flex flex-col gap-1.5">
                            <button
                                class="mc-step-btn"
                                title="Adicionar 5 minutos"
                                @click="ajustarMinutos(5)"
                            >
                                +5
                            </button>
                            <button
                                class="mc-step-btn"
                                title="Remover 5 minutos"
                                :disabled="excedido"
                                @click="ajustarMinutos(-5)"
                            >
                                −5
                            </button>
                        </div>
                        <div class="mc-display" :class="{ 'is-excedido': excedido }">
                            {{ display }}
                        </div>
                    </div>
                    <div class="text-xs mt-2 text-center" :class="excedido ? 'text-red-400 font-medium' : 'text-white/50'">
                        {{ excedido ? 'tempo excedido' : 'tempo restante' }}
                    </div>
                </div>

                <!-- Ações -->
                <div class="flex gap-3">
                    <button class="mc-btn mc-btn--secondary flex-1" @click="ajustarMinutos(1)">
                        +1 minuto
                    </button>
                    <button
                        class="mc-btn flex-1"
                        :class="running ? 'mc-btn--danger' : 'mc-btn--primary'"
                        @click="toggle"
                    >
                        <i :class="running ? 'pi pi-stop-circle' : 'pi pi-play'" class="text-xs" />
                        {{ running ? 'Parar' : 'Começar' }}
                    </button>
                </div>
            </div>
        </div>
    </Transition>

    <!-- Chip minimizado — teleporta pro .melissa-dock (taskbar Win11
         no bottom). Vive ao lado do ψ (à direita dele, dentro do flex
         do dock). Transition envolve o Teleport (pattern oficial Vue):
         o Teleport some/aparece como unidade, sem deixar comment
         placeholder no target compartilhado — o que evitaria o bug
         "emitsOptions: null" causado por múltiplos Teleports + v-if
         interno apontando pro mesmo target. -->
    <Transition name="chip-pop">
        <Teleport v-if="exists && minimized" to=".melissa-dock">
            <button
                class="mc-chip"
                title="Restaurar cronômetro"
                @click="restaurar"
            >
                <i
                    class="pi pi-stopwatch text-sm"
                    :class="running ? 'text-emerald-300 mc-chip-pulse' : 'text-white/70'"
                />
                <span class="mc-chip-time" :class="{ 'text-red-300': excedido }">
                    {{ display }}
                </span>
                <span class="mc-chip-name">{{ pacienteNome }}</span>
            </button>
        </Teleport>
    </Transition>
</template>

<style scoped>
/* ─── Dialog ───────────────────────────────────────────────── */
.mc-layer {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
}
.mc-panel {
    width: min(420px, 100%);
    background: var(--m-bg-medium);
    backdrop-filter: blur(32px) saturate(160%);
    -webkit-backdrop-filter: blur(32px) saturate(160%);
    border: 1px solid var(--m-border-strong);
    border-radius: 22px;
    padding: 1.75rem;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}

.mc-glass-btn {
    width: 36px;
    height: 36px;
    display: grid;
    place-items: center;
    background: var(--m-bg-soft);
    backdrop-filter: blur(20px);
    border: 1px solid var(--m-border-strong);
    border-radius: 9999px;
    cursor: pointer;
    transition: background-color 160ms ease;
}
.mc-glass-btn:hover {
    background: var(--m-bg-soft-hover);
}

/* ─── Select customizado ───────────────────────────────────── */
.mc-select {
    width: 100%;
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border-strong);
    color: var(--m-text);
    padding: 11px 38px 11px 14px;
    border-radius: 10px;
    font-size: 0.95rem;
    font-family: inherit;
    outline: none;
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    transition: border-color 140ms ease, background-color 140ms ease;
}
.mc-select:hover {
    background: var(--m-bg-soft-hover);
}
.mc-select:focus {
    border-color: var(--m-border-strong);
}
.mc-select option {
    /* renderizado pelo OS — usa tokens semânticos pra acompanhar dark/light */
    background: var(--p-content-background);
    color: var(--m-text);
}
.mc-select-icon {
    position: absolute;
    right: 14px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--m-text-muted);
    font-size: 0.7rem;
    pointer-events: none;
}

/* ─── Display gigante ──────────────────────────────────────── */
.mc-display {
    font-size: 5rem;
    font-weight: 200;
    line-height: 1;
    letter-spacing: -0.04em;
    color: var(--m-text);
    font-variant-numeric: tabular-nums;
    text-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
    transition: color 200ms ease;
}
.mc-display.is-excedido {
    color: #ef4444;
    text-shadow: 0 4px 24px rgba(239, 68, 68, 0.45);
    animation: mc-excedido-pulse 1.4s ease-in-out infinite;
}
@keyframes mc-excedido-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.65; }
}

/* ─── Steppers manuais (+5 / -5) ───────────────────────────── */
.mc-step-btn {
    width: 44px;
    height: 36px;
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border-strong);
    color: var(--m-text);
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    font-family: inherit;
    cursor: pointer;
    transition: background-color 140ms ease, border-color 140ms ease, transform 100ms ease;
}
.mc-step-btn:hover {
    background: var(--m-bg-soft-hover);
    border-color: var(--m-border-strong);
}
.mc-step-btn:active {
    transform: scale(0.96);
}
.mc-step-btn:disabled {
    background: var(--m-bg-soft);
    border-color: var(--m-border);
    color: var(--m-text-faint);
    cursor: not-allowed;
    pointer-events: none;
}

/* ─── Botões de ação ───────────────────────────────────────── */
.mc-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 12px 14px;
    border-radius: 12px;
    font-size: 0.9rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: background-color 140ms ease, border-color 140ms ease;
}
.mc-btn--secondary {
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border-strong);
    color: var(--m-text);
}
.mc-btn--secondary:hover {
    background: var(--m-bg-soft-hover);
    border-color: var(--m-border-strong);
}
.mc-btn--primary {
    background: var(--m-accent);
    border: 1px solid var(--m-accent);
    color: var(--p-primary-contrast-color, white);
}
.mc-btn--primary:hover {
    background: color-mix(in srgb, var(--m-accent) 80%, white);
}
.mc-btn--danger {
    background: rgba(239, 68, 68, 0.55);
    border: 1px solid rgba(239, 68, 68, 0.7);
    color: white;
}
.mc-btn--danger:hover {
    background: rgba(239, 68, 68, 0.75);
}

/* ─── Chip minimizado (teleportado pro .melissa-dock) ──────
   Vive como filho flex do dock — não usa position fixed. Dock
   posiciona ele à esquerda (depois do ψ, via padding-left). */
.mc-chip {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px 8px 12px;
    background: var(--m-bg-medium);
    backdrop-filter: blur(24px) saturate(160%);
    -webkit-backdrop-filter: blur(24px) saturate(160%);
    border: 1px solid var(--m-border-strong);
    border-radius: 9999px;
    color: var(--m-text);
    cursor: pointer;
    transition: background-color 200ms ease, transform 200ms ease, border-color 200ms ease;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
.mc-chip:hover {
    background: var(--m-bg-medium);
    transform: translateY(-2px);
    border-color: var(--m-border-strong);
}
.mc-chip-time {
    font-variant-numeric: tabular-nums;
    font-weight: 500;
    font-size: 0.85rem;
}
.mc-chip-name {
    font-size: 0.72rem;
    color: var(--m-text-muted);
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding-left: 6px;
    border-left: 1px solid var(--m-border-strong);
}
.mc-chip-pulse {
    animation: mc-pulse 1.6s ease-in-out infinite;
}
@keyframes mc-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

/* ─── Transições ───────────────────────────────────────────── */
.lift-enter-active,
.lift-leave-active {
    transition: opacity 240ms ease, transform 280ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.lift-enter-from {
    opacity: 0;
    transform: scale(0.96) translateY(12px);
}
.lift-leave-to {
    opacity: 0;
    transform: scale(0.98) translateY(8px);
}

.chip-pop-enter-active,
.chip-pop-leave-active {
    transition: opacity 200ms ease, transform 220ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.chip-pop-enter-from,
.chip-pop-leave-to {
    opacity: 0;
    transform: scale(0.85) translateY(-8px);
}
/* Chip aparecendo após minimize: leve atraso pra deixar o dialog
   "voar" antes de aparecer no dock (sensação macOS) */
.chip-pop-enter-active {
    transition-delay: 120ms;
}

/* ─── Animação "minimize" (macOS-style): dialog encolhe + voa pro
   bottom-left em direção ao chip que vai aparecer no dock. Aplicada
   só durante minimizar() — fechar normal usa lift. ────────────── */
.minimize-enter-active,
.minimize-leave-active {
    transition: opacity 280ms ease, transform 340ms cubic-bezier(0.5, 0, 0.6, 1);
    /* origem ~= posição do chip no dock (left:96px após ψ, bottom centro
       da faixa de 76px = ~38px). Faz o scale "encolher em direção" lá. */
    transform-origin: 96px calc(100% - 38px);
}
.minimize-enter-from {
    opacity: 0;
    transform: scale(0.05);
}
.minimize-leave-to {
    opacity: 0;
    transform: scale(0.05);
}

/* ─── Light mode tweaks ────────────────────────────────────
   Texto já usa var(--m-text) (flipa automático), mas alguns
   shadows escuros agressivos precisam ser suavizados. */
html:not(.app-dark) .mc-display {
    text-shadow: none;
}
html:not(.app-dark) .mc-chip {
    box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08), 0 1px 3px rgba(15, 23, 42, 0.06);
}
html:not(.app-dark) .mc-panel {
    box-shadow: 0 12px 36px rgba(15, 23, 42, 0.12), 0 2px 6px rgba(15, 23, 42, 0.06);
}
</style>
