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

import Dropdown from 'primevue/dropdown';
import { useToast } from 'primevue/usetoast';
import { useConfirm } from 'primevue/useconfirm';

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

const loading = ref(false);
const savingId = ref(null);
const isFetching = ref(false);

const plans = ref([]);
const subs = ref([]);

const q = ref('');

// filtro tipo
const typeFilter = ref('all'); // 'all' | 'clinic' | 'therapist'
const typeOptions = [
    { label: 'Todos', value: 'all' },
    { label: 'Clínica', value: 'clinic' },
    { label: 'Terapeuta', value: 'therapist' }
];

const isFocused = computed(() => {
    return typeof route.query?.q === 'string' && route.query.q.trim().length > 0;
});

// -------------------------
// ownerKey helpers
// -------------------------
function parseOwnerKey(raw) {
    const s = String(raw || '').trim();
    if (!s) return { kind: 'unknown', id: null, raw: '' };

    const m = s.match(/^(clinic|therapist)\s*:\s*([0-9a-fA-F-]{8,})$/);
    if (m) return { kind: m[1].toLowerCase(), id: m[2], raw: s };

    return { kind: 'unknown', id: s, raw: s };
}

function subscriptionType(s) {
    if (s?.tenant_id) return 'clinic';
    if (s?.user_id && !s?.tenant_id) return 'therapist';
    return 'unknown';
}

function ownerKey(s) {
    const t = subscriptionType(s);
    if (t === 'clinic') return `clinic:${s.tenant_id}`;
    if (t === 'therapist') return `therapist:${s.user_id}`;
    return String(s?.user_id || s?.tenant_id || '(desconhecido)');
}

function typeLabel(t) {
    if (t === 'clinic') return 'Clínica';
    if (t === 'therapist') return 'Terapeuta';
    return '—';
}

function typeSeverity(t) {
    if (t === 'clinic') return 'info';
    if (t === 'therapist') return 'success';
    return 'secondary';
}

function statusLabel(st) {
    const s = String(st || '').toLowerCase();
    if (s === 'active') return 'Ativa';
    if (s === 'trialing') return 'Teste';
    if (s === 'past_due') return 'Em atraso';
    if (s === 'canceled' || s === 'cancelled') return 'Cancelada';
    if (!s) return '—';
    return st;
}

function statusSeverity(st) {
    const s = String(st || '').toLowerCase();
    if (s === 'active') return 'success';
    if (s === 'trialing') return 'info';
    if (s === 'past_due') return 'warning';
    if (s === 'canceled' || s === 'cancelled') return 'danger';
    return 'secondary';
}

function intervalLabel(itv) {
    const s = String(itv || '').toLowerCase();
    if (!s) return '—';
    if (s === 'month') return 'Mensal';
    if (s === 'year') return 'Anual';
    return s;
}

function fmtDate(v) {
    if (!v) return '—';
    const d = new Date(v);
    if (Number.isNaN(d.getTime())) return String(v);
    return d.toLocaleString('pt-BR');
}

// -------------------------
// fetch
// -------------------------
async function fetchAll() {
    if (isFetching.value) return;
    isFetching.value = true;
    loading.value = true;

    try {
        const [{ data: p, error: ep }, { data: s, error: es }] = await Promise.all([
            supabase.from('plans').select('id,key,target,is_active').order('key', { ascending: true }),

            supabase.from('subscriptions').select('id,tenant_id,user_id,plan_id,status,interval,current_period_start,current_period_end,updated_at,created_at,plan_key').order('updated_at', { ascending: false })
        ]);

        if (ep) throw ep;
        if (es) throw es;

        plans.value = p || [];
        subs.value = s || [];
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e.message || String(e), life: 5000 });
    } finally {
        loading.value = false;
        isFetching.value = false;
    }
}

// -------------------------
// plans helpers
// -------------------------
function planById(planId) {
    return plans.value.find((x) => String(x.id) === String(planId)) || null;
}

function planKeyById(planId) {
    return planById(planId)?.key || null;
}

function planLabelForRow(subRow) {
    return planKeyById(subRow?.plan_id) || subRow?.plan_key || '(sem plano)';
}

function severityForPlan(key) {
    const k = String(key || '').toLowerCase();
    if (!k) return 'secondary';
    return k.includes('pro') ? 'success' : 'info';
}

function plansForSub(subRow) {
    const t = subscriptionType(subRow);
    if (t !== 'clinic' && t !== 'therapist') return [];

    return (plans.value || []).filter((p) => {
        if (p?.target && p.target !== t) return false;
        if (p?.is_active === false) return false;
        return true;
    });
}

function canChangePlan(subRow) {
    const t = subscriptionType(subRow);
    return t === 'clinic' || t === 'therapist';
}

function canCancel(row) {
    const s = String(row?.status || '').toLowerCase();
    return s === 'active' || s === 'trialing' || s === 'past_due';
}

// -------------------------
// update plan (com confirmação)
// -------------------------
function confirmUpdatePlan(subRow, nextPlanId) {
    if (!nextPlanId) return;
    if (String(nextPlanId) === String(subRow.plan_id)) return;
    if (loading.value || savingId.value) return;

    const t = subscriptionType(subRow);
    const owner = ownerKey(subRow);
    const next = planById(nextPlanId);
    const prevKey = planLabelForRow(subRow);

    if (!next) return;

    if (next.target && next.target !== t) {
        toast.add({
            severity: 'warn',
            summary: 'Plano incompatível',
            detail: `Essa assinatura é ${typeLabel(t)}. Selecione um plano ${typeLabel(t)}.`,
            life: 4200
        });
        return;
    }

    confirm.require({
        header: 'Confirmar mudança de plano',
        message: `Trocar de "${prevKey}" para "${next.key}" em ${owner}?`,
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-warning',
        accept: () => updatePlan(subRow, nextPlanId)
    });
}

async function updatePlan(subRow, nextPlanId) {
    const prev = subRow.plan_id;
    subRow.plan_id = nextPlanId;
    savingId.value = subRow.id;

    try {
        const { data, error } = await supabase.rpc('change_subscription_plan', {
            p_subscription_id: subRow.id,
            p_new_plan_id: nextPlanId
        });
        if (error) throw error;

        if (data?.plan_id) subRow.plan_id = data.plan_id;

        toast.add({ severity: 'success', summary: 'Ok', detail: 'Plano atualizado.', life: 2500 });

        await fetchAll();
    } catch (e) {
        subRow.plan_id = prev;
        toast.add({ severity: 'error', summary: 'Erro', detail: e.message || String(e), life: 5000 });
    } finally {
        savingId.value = null;
    }
}

// -------------------------
// cancel / reactivate (com confirmação)
// -------------------------
function confirmCancel(row) {
    if (!row?.id) return;
    const owner = ownerKey(row);

    confirm.require({
        header: 'Confirmar cancelamento',
        message: `Cancelar assinatura de ${owner}?`,
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-danger',
        accept: () => cancelSubscription(row)
    });
}

async function cancelSubscription(row) {
    savingId.value = row.id;
    try {
        const { error } = await supabase.rpc('cancel_subscription', {
            p_subscription_id: row.id
        });
        if (error) throw error;

        toast.add({ severity: 'success', summary: 'Cancelada', life: 2500 });
        await fetchAll();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e.message || String(e), life: 5000 });
    } finally {
        savingId.value = null;
    }
}

function confirmReactivate(row) {
    if (!row?.id) return;
    const owner = ownerKey(row);

    confirm.require({
        header: 'Confirmar reativação',
        message: `Reativar assinatura de ${owner}?`,
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-success',
        accept: () => reactivateSubscription(row)
    });
}

async function reactivateSubscription(row) {
    savingId.value = row.id;
    try {
        const { error } = await supabase.rpc('reactivate_subscription', {
            p_subscription_id: row.id
        });
        if (error) throw error;

        toast.add({ severity: 'success', summary: 'Reativada', life: 2500 });
        await fetchAll();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e.message || String(e), life: 5000 });
    } finally {
        savingId.value = null;
    }
}

// -------------------------
// foco por query
// -------------------------
function matchesFocused(s, rawQ) {
    const parsed = parseOwnerKey(rawQ);
    if (parsed.kind === 'clinic') return String(s.tenant_id || '') === String(parsed.id || '');
    if (parsed.kind === 'therapist') return String(s.user_id || '') === String(parsed.id || '');

    const hay = [ownerKey(s), s.tenant_id, s.user_id, s.status, s.interval, planLabelForRow(s)].map((x) => String(x || '').toLowerCase());

    return hay.some((x) => x.includes(String(rawQ || '').toLowerCase()));
}

// -------------------------
// filtro + busca
// -------------------------
const filteredSubs = computed(() => {
    const term = String(q.value || '')
        .trim()
        .toLowerCase();
    let list = subs.value || [];

    if (typeFilter.value !== 'all') {
        list = list.filter((s) => subscriptionType(s) === typeFilter.value);
    }

    const rawQ = String(route.query?.q || '').trim();
    if (rawQ) {
        list = list.filter((s) => matchesFocused(s, rawQ));
    }

    if (!term) return list;

    return list.filter((s) => {
        const a = String(ownerKey(s) || '').toLowerCase();
        const b = String(s.status || '').toLowerCase();
        const c = String(planLabelForRow(s) || '').toLowerCase();
        const d = String(s.interval || '').toLowerCase();
        const e = String(s.tenant_id || '').toLowerCase();
        const f = String(s.user_id || '').toLowerCase();

        return a.includes(term) || b.includes(term) || c.includes(term) || d.includes(term) || e.includes(term) || f.includes(term);
    });
});

const totalCount = computed(() => (filteredSubs.value || []).length);
const activeCount = computed(() => (filteredSubs.value || []).filter((x) => String(x?.status || '').toLowerCase() === 'active').length);

function clearFocus() {
    router.push({ path: route.path, query: {} });
}

// -------------------------
// Hero sticky
// -------------------------
const heroRef = ref(null);
const sentinelRef = ref(null);
const heroStuck = ref(false);
let heroObserver = null;
const mobileMenuRef = ref(null);

const heroMenuItems = computed(() => [
    {
        label: 'Recarregar',
        icon: 'pi pi-refresh',
        command: fetchAll,
        disabled: loading.value || savingId.value !== null
    },
    { separator: true },
    {
        label: 'Filtros',
        items: typeOptions.map((o) => ({
            label: o.label,
            icon: typeFilter.value === o.value ? 'pi pi-check' : 'pi pi-circle',
            command: () => {
                typeFilter.value = o.value;
            }
        }))
    }
]);

onMounted(async () => {
    const initialQ = route.query?.q;
    if (typeof initialQ === 'string' && initialQ.trim()) {
        q.value = initialQ.trim();

        const parsed = parseOwnerKey(initialQ);
        if (parsed.kind === 'clinic') typeFilter.value = 'clinic';
        if (parsed.kind === 'therapist') typeFilter.value = 'therapist';
    }

    await fetchAll();

    if (sentinelRef.value) {
        heroObserver = new IntersectionObserver(
            ([entry]) => {
                heroStuck.value = !entry.isIntersecting;
            },
            { rootMargin: `${document.querySelector('.l2-main') ? '0px' : '-56px'} 0px 0px 0px`, threshold: 0 }
        );
        heroObserver.observe(sentinelRef.value);
    }
});

onBeforeUnmount(() => {
    heroObserver?.disconnect();
});
</script>

<template>
    <ConfirmDialog />

    <div class="flex flex-col gap-4 p-4">
        <!-- Header -->
        <div class="cfg-subheader">
            <div class="cfg-subheader__icon"><i class="pi pi-credit-card" /></div>
            <div class="min-w-0 flex-1">
                <div class="cfg-subheader__title">Assinaturas</div>
                <div class="cfg-subheader__sub">Painel operacional do SaaS: revise plano, status e período (Clínica x Terapeuta) com segurança.</div>
            </div>
            <div class="hidden xl:flex items-center gap-2 shrink-0">
                <SelectButton v-model="typeFilter" :options="typeOptions" optionLabel="label" optionValue="value" size="small" :disabled="loading || savingId !== null" />
                <Button label="Recarregar" icon="pi pi-refresh" severity="secondary" outlined size="small" :loading="loading" :disabled="savingId !== null" @click="fetchAll" />
            </div>
            <div class="flex xl:hidden shrink-0">
                <Button label="Ações" icon="pi pi-ellipsis-v" severity="warn" size="small" @click="(e) => mobileMenuRef.toggle(e)" />
                <Menu ref="mobileMenuRef" :model="heroMenuItems" popup />
            </div>
        </div>
        <!-- Header foco -->
        <div v-if="isFocused" class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-4">
            <div class="flex align-items-center justify-content-between gap-3 flex-wrap">
                <div>
                    <div class="text-[1rem] font-semibold text-[var(--text-color)]">Assinatura em foco</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)]">Filtro: {{ route.query.q }}</div>
                </div>

                <Button label="Limpar filtro" icon="pi pi-times" severity="secondary" outlined :disabled="loading || savingId !== null" @click="clearFocus" />
            </div>
        </div>

        <!-- busca -->
        <div>
            <FloatLabel variant="on" class="w-full">
                <IconField class="w-full">
                    <InputIcon class="pi pi-search" />
                    <InputText v-model="q" id="subs_search" class="w-full pr-10" variant="filled" :disabled="loading" />
                </IconField>
                <label for="subs_search">Buscar owner, status, intervalo, plano…</label>
            </FloatLabel>
        </div>

        <DataTable
            :value="filteredSubs"
            dataKey="id"
            :loading="loading"
            stripedRows
            responsiveLayout="scroll"
            :rowHover="true"
            paginator
            :rows="15"
            :rowsPerPageOptions="[10, 15, 25, 50]"
            currentPageReportTemplate="{first}–{last} de {totalRecords}"
            paginatorTemplate="RowsPerPageDropdown FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport"
        >
            <Column header="Tipo" style="width: 10rem">
                <template #body="{ data }">
                    <Tag :value="typeLabel(subscriptionType(data))" :severity="typeSeverity(subscriptionType(data))" rounded />
                </template>
            </Column>

            <Column header="Owner" style="min-width: 22rem">
                <template #body="{ data }">
                    <div class="flex flex-col">
                        <span class="font-medium">{{ ownerKey(data) }}</span>
                        <div class="text-[1rem] text-[var(--text-color-secondary)]">
                            {{ data.tenant_id ? `tenant_id: ${data.tenant_id}` : `user_id: ${data.user_id || '—'}` }}
                        </div>
                    </div>
                </template>
            </Column>

            <Column header="Plano" style="min-width: 18rem">
                <template #body="{ data }">
                    <div class="flex items-center gap-2 flex-wrap">
                        <Tag :value="planLabelForRow(data)" :severity="severityForPlan(planLabelForRow(data))" />

                        <Dropdown
                            v-if="canChangePlan(data)"
                            :modelValue="data.plan_id"
                            :options="plansForSub(data)"
                            optionLabel="key"
                            optionValue="id"
                            placeholder="Selecione..."
                            class="w-14rem"
                            :disabled="savingId === data.id || loading"
                            @update:modelValue="(val) => confirmUpdatePlan(data, val)"
                        />

                        <Tag v-else value="tipo inválido" severity="warning" />
                    </div>
                </template>
            </Column>

            <Column header="Intervalo" style="width: 10rem">
                <template #body="{ data }">
                    <Tag :value="intervalLabel(data.interval)" severity="secondary" />
                </template>
            </Column>

            <Column header="Período" style="min-width: 18rem">
                <template #body="{ data }">
                    <div>
                        <div>{{ fmtDate(data.current_period_start) }}</div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)]">até {{ fmtDate(data.current_period_end) }}</div>
                    </div>
                </template>
            </Column>

            <Column header="Status" style="width: 10rem">
                <template #body="{ data }">
                    <Tag :value="statusLabel(data.status)" :severity="statusSeverity(data.status)" />
                </template>
            </Column>

            <Column header="Atualizado" style="min-width: 14rem">
                <template #body="{ data }">
                    {{ fmtDate(data.updated_at) }}
                </template>
            </Column>

            <Column header="Ações" style="min-width: 14rem">
                <template #body="{ data }">
                    <div class="flex gap-2 flex-wrap">
                        <Button icon="pi pi-history" severity="secondary" outlined :disabled="loading || savingId !== null" v-tooltip.top="'Ver histórico'" @click="router.push('/saas/subscription-events?q=' + ownerKey(data))" />

                        <Button
                            v-if="canCancel(data)"
                            icon="pi pi-ban"
                            severity="danger"
                            outlined
                            v-tooltip.top="'Cancelar'"
                            :loading="savingId === data.id"
                            :disabled="loading || (savingId !== null && savingId !== data.id)"
                            @click="confirmCancel(data)"
                        />

                        <Button v-else icon="pi pi-refresh" severity="success" outlined v-tooltip.top="'Reativar'" :loading="savingId === data.id" :disabled="loading || (savingId !== null && savingId !== data.id)" @click="confirmReactivate(data)" />
                    </div>
                </template>
            </Column>

            <template #empty>
                <div class="p-4 text-[var(--text-color-secondary)]">Nenhuma assinatura encontrada com os filtros atuais.</div>
            </template>
        </DataTable>
    </div>
</template>