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

import { useToast } from 'primevue/usetoast';

import { supabase } from '@/lib/supabase/client';

const toast = useToast();
const route = useRoute();
const router = useRouter();

const loading = ref(false);
const saving = ref(false);
const isFetching = ref(false);

const uid = ref(null);
const currentSub = ref(null);

const plans = ref([]); // plans (therapist)
const prices = ref([]); // plan_prices ativos do momento

const q = ref('');

const billingInterval = ref('month'); // 'month' | 'year'
const intervalOptions = [
    { label: 'Mensal', value: 'month' },
    { label: 'Anual', value: 'year' }
];

const redirectTo = computed(() => route.query.redirectTo || '/therapist/meu-plano');

function money(currency, amountCents) {
    if (amountCents == null) return null;
    const value = Number(amountCents) / 100;
    try {
        return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: currency || 'BRL' }).format(value);
    } catch (_) {
        return `${value.toFixed(2)} ${currency || ''}`.trim();
    }
}

function intervalLabel(i) {
    if (i === 'month') return 'mês';
    if (i === 'year') return 'ano';
    return i || '-';
}

function priceFor(planId, interval) {
    return (prices.value || []).find((p) => String(p.plan_id) === String(planId) && String(p.interval) === String(interval)) || null;
}

function priceLabelForCard(planRow) {
    const pp = priceFor(planRow?.id, billingInterval.value);
    if (!pp) return '—';
    return `${money(pp.currency, pp.amount_cents)} / ${intervalLabel(billingInterval.value)}`;
}

const filteredPlans = computed(() => {
    const term = String(q.value || '')
        .trim()
        .toLowerCase();
    if (!term) return plans.value || [];
    return (plans.value || []).filter((p) => {
        const a = String(p.key || '').toLowerCase();
        const b = String(p.name || '').toLowerCase();
        const c = String(p.description || '').toLowerCase();
        return a.includes(term) || b.includes(term) || c.includes(term);
    });
});

async function loadData() {
    if (isFetching.value) return;
    isFetching.value = true;
    loading.value = true;

    try {
        const { data: authData, error: authError } = await supabase.auth.getUser();
        if (authError) throw authError;

        uid.value = authData?.user?.id;
        if (!uid.value) throw new Error('Sessão não encontrada.');

        // assinatura pessoal atual (Modelo A): busca por user_id, prioriza status ativo
        const sRes = await supabase.from('subscriptions').select('*').eq('user_id', uid.value).order('created_at', { ascending: false }).limit(10);

        if (sRes.error) throw sRes.error;

        const subList = sRes.data || [];
        const subPriority = (st) => {
            const s = String(st || '').toLowerCase();
            if (s === 'active') return 1;
            if (s === 'trialing') return 2;
            if (s === 'past_due') return 3;
            if (s === 'unpaid') return 4;
            if (s === 'incomplete') return 5;
            if (s === 'canceled' || s === 'cancelled') return 9;
            return 8;
        };
        currentSub.value = subList.length
            ? subList.slice().sort((a, b) => {
                  const pa = subPriority(a?.status);
                  const pb = subPriority(b?.status);
                  if (pa !== pb) return pa - pb;
                  return new Date(b?.created_at || 0) - new Date(a?.created_at || 0);
              })[0]
            : null;

        // planos do terapeuta (target = therapist)
        const pRes = await supabase.from('plans').select('id, key, name, description, target, is_active').eq('target', 'therapist').order('created_at', { ascending: true });

        if (pRes.error) throw pRes.error;
        plans.value = (pRes.data || []).filter((p) => p?.is_active !== false);

        // preços ativos (janela de vigência)
        const nowIso = new Date().toISOString();
        const ppRes = await supabase
            .from('plan_prices')
            .select('plan_id, currency, interval, amount_cents, is_active, active_from, active_to')
            .eq('is_active', true)
            .lte('active_from', nowIso)
            .or(`active_to.is.null,active_to.gte.${nowIso}`)
            .order('active_from', { ascending: false });

        if (ppRes.error) throw ppRes.error;
        prices.value = ppRes.data || [];
    } catch (e) {
        console.error(e);
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 5000 });
    } finally {
        loading.value = false;
        isFetching.value = false;
    }
}

function preflight(planRow, interval) {
    if (!uid.value) return { ok: false, msg: 'Sessão não encontrada.' };
    if (!planRow?.id) return { ok: false, msg: 'Plano inválido.' };
    if (!['month', 'year'].includes(String(interval))) return { ok: false, msg: 'Intervalo inválido.' };

    const pp = priceFor(planRow.id, interval);
    if (!pp) {
        return { ok: false, msg: `Este plano não tem preço ativo para ${intervalLabel(interval)}.` };
    }

    // se já estiver nesse plano+intervalo, evita ação
    if (currentSub.value?.plan_id === planRow.id && String(currentSub.value?.interval) === String(interval)) {
        return { ok: false, msg: 'Você já está nesse plano/intervalo.' };
    }

    return { ok: true, msg: '' };
}

/**
 * ✅ Fluxo seguro:
 * - se já existe subscription => chama RPC change_subscription_plan (audita + triggers)
 * - se não existe => cria subscription mínima e depois (opcional) roda rebuild_owner_entitlements
 *
 * Observação:
 * - aqui eu assumo que você tem `change_subscription_plan(p_subscription_id, p_new_plan_id)`
 *   e que interval pode ser alterado por update simples ou outro RPC.
 * - se você tiver um RPC específico para intervalo, só troca abaixo.
 */
async function choosePlan(planRow, interval) {
    const pf = preflight(planRow, interval);
    if (!pf.ok) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: pf.msg, life: 4200 });
        return;
    }

    saving.value = true;
    try {
        const nowIso = new Date().toISOString();

        if (currentSub.value?.id) {
            // 1) troca plano via RPC (auditoria)
            const { error: e1 } = await supabase.rpc('change_subscription_plan', {
                p_subscription_id: currentSub.value.id,
                p_new_plan_id: planRow.id
            });
            if (e1) throw e1;

            // 2) atualiza intervalo (se o seu RPC já faz isso, pode remover)
            const { error: e2 } = await supabase
                .from('subscriptions')
                .update({
                    interval,
                    updated_at: nowIso,
                    cancel_at_period_end: false,
                    status: 'active'
                })
                .eq('id', currentSub.value.id);
            if (e2) throw e2;
        } else {
            // cria subscription pessoal
            const { data: ins, error: eIns } = await supabase
                .from('subscriptions')
                .insert({
                    user_id: uid.value,
                    tenant_id: null,
                    plan_id: planRow.id,
                    plan_key: planRow.key,
                    interval,
                    status: 'active',
                    cancel_at_period_end: false,
                    provider: 'manual',
                    source: 'therapist_upgrade',
                    started_at: nowIso,
                    current_period_start: nowIso
                })
                .select('*')
                .maybeSingle();

            if (eIns) throw eIns;
            currentSub.value = ins || null;
        }

        // (opcional) se sua regra de entitlements depende disso, você pode rebuildar aqui:
        // await supabase.rpc('rebuild_owner_entitlements', { p_owner_id: uid.value })

        toast.add({
            severity: 'success',
            summary: 'Plano atualizado',
            detail: 'Seu plano foi atualizado com sucesso.',
            life: 3200
        });

        // ✅ garante refletir estado real
        await loadData();

        // redirect
        await router.push(String(redirectTo.value));
    } catch (e) {
        console.error(e);
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 5000 });
    } finally {
        saving.value = false;
    }
}

function goBack() {
    router.push(String(redirectTo.value));
}

onMounted(loadData);
</script>

<template>
    <!-- Sentinel -->
    <div class="h-px" />

    <!-- ══════════════════════════════════════════════════════
       HERO sticky
  ═══════════════════════════════════════════════════════ -->
    <section class="sticky mx-3 md:mx-4 my-3 z-20 overflow-hidden rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] px-3 py-2.5" :style="{ top: 'var(--layout-sticky-top, 56px)' }">
        <!-- Blobs -->
        <div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
            <div class="absolute w-64 h-64 -top-16 -right-8 rounded-full blur-[60px] bg-indigo-500/10" />
            <div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-emerald-400/[0.08]" />
        </div>

        <div class="relative z-1 flex flex-col gap-2.5">
            <!-- Linha 1: brand + busca + ações -->
            <div class="flex items-center gap-3 flex-wrap">
                <!-- Brand -->
                <div class="flex items-center gap-2 shrink-0">
                    <div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
                        <i class="pi pi-arrow-up-right text-base" />
                    </div>
                    <div class="min-w-0 hidden sm:block">
                        <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">Upgrade do Terapeuta</div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)]">Escolha seu plano pessoal (Modelo A)</div>
                    </div>
                </div>

                <!-- Busca desktop -->
                <div class="hidden md:flex flex-1 min-w-[180px] max-w-xs">
                    <IconField class="w-full">
                        <InputIcon class="pi pi-search" />
                        <InputText v-model="q" placeholder="Buscar plano..." class="w-full" autocomplete="off" :disabled="loading || saving" />
                    </IconField>
                </div>

                <!-- Ações -->
                <div class="flex items-center gap-1 shrink-0 ml-auto">
                    <Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full shrink-0" :loading="loading" :disabled="saving" title="Atualizar" @click="loadData" />
                    <Button label="Voltar" icon="pi pi-arrow-left" severity="secondary" outlined class="rounded-full" :disabled="saving" @click="goBack" />
                </div>
            </div>

            <!-- Linha 2: busca mobile + seletor de intervalo -->
            <div class="flex flex-wrap items-center gap-2">
                <!-- Busca mobile -->
                <div class="flex md:hidden flex-1 min-w-[160px]">
                    <IconField class="w-full">
                        <InputIcon class="pi pi-search" />
                        <InputText v-model="q" placeholder="Buscar plano..." class="w-full" autocomplete="off" :disabled="loading || saving" />
                    </IconField>
                </div>

                <!-- Intervalo chips -->
                <div class="flex items-center gap-1.5 shrink-0">
                    <span class="text-[1rem] text-[var(--text-color-secondary)] opacity-70 hidden sm:inline">Preço:</span>
                    <button
                        v-for="opt in intervalOptions"
                        :key="opt.value"
                        class="inline-flex items-center gap-1.5 px-3.5 py-1 rounded-full text-[1rem] font-semibold border-[1.5px] cursor-pointer transition-all duration-150 select-none"
                        :class="
                            billingInterval === opt.value
                                ? 'bg-[var(--primary-color,#6366f1)] border-[var(--primary-color,#6366f1)] text-white'
                                : 'border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] text-[var(--text-color-secondary)] hover:border-indigo-300 hover:text-[var(--text-color)]'
                        "
                        :disabled="loading || saving"
                        @click="billingInterval = opt.value"
                    >
                        {{ opt.label }}
                    </button>
                </div>

                <!-- Plano atual -->
                <Tag v-if="currentSub" :value="`Atual: ${currentSub.plan_key} · ${intervalLabel(currentSub.interval)}`" severity="success" />
                <Tag v-else value="Sem plano pessoal" severity="warning" />
            </div>
        </div>
    </section>

    <!-- ══════════════════════════════════════════════════════
       QUICK-STATS
  ═══════════════════════════════════════════════════════ -->
    <div class="flex flex-wrap gap-2 px-3 md:px-4 mb-3">
        <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[80px] border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]">
            <div class="text-[1.35rem] font-bold leading-none text-[var(--text-color)]">{{ filteredPlans.length }}</div>
            <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75">Planos disponíveis</div>
        </div>
        <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[80px] border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]">
            <div class="text-[1.1rem] font-bold leading-none text-[var(--text-color)] truncate">{{ currentSub?.plan_key || '—' }}</div>
            <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75">Plano atual</div>
        </div>
        <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[80px] border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]">
            <div class="text-[1.1rem] font-bold leading-none text-[var(--text-color)]">{{ billingInterval === 'month' ? 'Mensal' : 'Anual' }}</div>
            <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75">Exibição de preço</div>
        </div>
    </div>

    <!-- ══════════════════════════════════════════════════════
       PLANOS
  ═══════════════════════════════════════════════════════ -->
    <div class="px-3 md:px-4 pb-8">
        <!-- Loading skeleton -->
        <div v-if="loading" class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3">
            <div v-for="n in 3" :key="n" class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] p-4">
                <div class="flex flex-col gap-3">
                    <div class="h-4 w-2/5 rounded-md bg-[var(--surface-border,#e2e8f0)] animate-pulse" />
                    <div class="h-3 w-3/5 rounded-md bg-[var(--surface-border,#e2e8f0)] animate-pulse" />
                    <div class="h-8 w-1/3 rounded-md bg-[var(--surface-border,#e2e8f0)] animate-pulse" />
                </div>
            </div>
        </div>

        <!-- Empty state -->
        <div v-else-if="!filteredPlans.length" class="flex flex-col items-center justify-center gap-4 rounded-md border-2 border-dashed border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] py-16 px-6 text-center">
            <div class="relative">
                <div class="grid place-items-center w-16 h-16 rounded-2xl bg-[var(--surface-card,#fff)] border border-[var(--surface-border,#e2e8f0)] shadow-sm text-[var(--text-color-secondary)]">
                    <i class="pi pi-box text-3xl opacity-30" />
                </div>
                <div class="absolute -top-2 -right-2 w-7 h-7 rounded-full bg-[var(--surface-card,#fff)] border border-[var(--surface-border,#e2e8f0)] shadow-sm grid place-items-center">
                    <i class="pi pi-times text-[0.65rem] text-[var(--text-color-secondary)] opacity-50" />
                </div>
            </div>
            <div>
                <div class="font-bold text-[1rem] text-[var(--text-color)] mb-1">Nenhum plano encontrado</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] max-w-xs leading-relaxed">Tente limpar o filtro de busca.</div>
            </div>
            <Button label="Limpar busca" icon="pi pi-filter-slash" severity="secondary" outlined class="rounded-full mt-1" @click="q = ''" />
        </div>

        <!-- Grid de planos -->
        <div v-else class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3">
            <div
                v-for="p in filteredPlans"
                :key="p.id"
                class="rounded-md border bg-[var(--surface-card,#fff)] overflow-hidden flex flex-col transition-shadow duration-150 hover:shadow-[0_4px_18px_rgba(0,0,0,0.07)]"
                :class="currentSub?.plan_id === p.id ? 'border-emerald-400/40 ring-1 ring-emerald-500/20' : 'border-[var(--surface-border,#e2e8f0)]'"
            >
                <!-- Cabeçalho do card -->
                <div class="flex items-center justify-between px-4 py-3 border-b border-[var(--surface-border,#e2e8f0)]">
                    <div class="min-w-0">
                        <div class="font-bold text-[0.9rem] text-[var(--text-color)] truncate">{{ p.name || p.key }}</div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)]">{{ p.key }}</div>
                    </div>
                    <Tag v-if="currentSub?.plan_id === p.id" severity="success" value="Atual" />
                </div>

                <!-- Corpo do card -->
                <div class="p-4 flex flex-col gap-4 flex-1">
                    <!-- Descrição -->
                    <div v-if="p.description" class="text-[1rem] text-[var(--text-color-secondary)]">{{ p.description }}</div>

                    <!-- Preço -->
                    <div>
                        <div class="text-[2rem] font-bold leading-none text-[var(--text-color)]">{{ priceLabelForCard(p) }}</div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1 opacity-70">Alternar mensal/anual no topo para comparar.</div>
                    </div>

                    <!-- Ações -->
                    <div class="flex flex-col gap-2 mt-auto">
                        <Button :label="billingInterval === 'month' ? 'Escolher mensal' : 'Escolher anual'" icon="pi pi-check" class="rounded-full w-full" :loading="saving" :disabled="loading || saving" @click="choosePlan(p, billingInterval)" />
                        <div class="flex gap-2">
                            <Button label="Mensal" severity="secondary" outlined class="rounded-full flex-1" :disabled="loading || saving" @click="choosePlan(p, 'month')" />
                            <Button label="Anual" severity="secondary" outlined class="rounded-full flex-1" :disabled="loading || saving" @click="choosePlan(p, 'year')" />
                        </div>
                    </div>

                    <!-- Status do preço -->
                    <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-60">
                        <span v-if="priceFor(p.id, billingInterval)">Preço ativo encontrado para {{ intervalLabel(billingInterval) }}.</span>
                        <span v-else>Sem preço ativo para {{ intervalLabel(billingInterval) }}.</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
