<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/components/agenda/AgendaEventoFinanceiroPanel.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->

<!--
  AgendaEventoFinanceiroPanel
  ───────────────────────────
  Painel compacto de status financeiro exibido dentro do modal de sessão.
  Mostra o financial_record vinculado ao evento e permite registrar pagamento
  ou gerar cobrança sem sair do contexto da agenda.

  Props:
    evento  — linha de agenda_eventos (deve ter: id, tipo, billed,
              billing_contract_id, price, patient_id, inicio_em)

  Emits:
    cobranca-atualizada — após qualquer mutação, para o pai recarregar
-->
<script setup>
import { ref, computed, watch } from 'vue';
import { useToast } from 'primevue/usetoast';
import { useConfirm } from 'primevue/useconfirm';

import { supabase } from '@/lib/supabase/client';
import { tenantDb } from '@/lib/supabase/tenantClient';
import { useTenantStore } from '@/stores/tenantStore';
import { useAgendaFinanceiro } from '@/composables/useAgendaFinanceiro';
import { emitirReciboParaSessao } from '@/services/DocumentGenerate.service';

// ── props / emits ─────────────────────────────────────────────────────────────
const props = defineProps({
    evento: {
        type: Object,
        required: true
    }
});

const emit = defineEmits(['cobranca-atualizada']);

// ── external ──────────────────────────────────────────────────────────────────
const toast = useToast();
const confirm = useConfirm();
const tenantStore = useTenantStore();
const { gerarCobrancaManual, loading: finLoading, error: finError } = useAgendaFinanceiro();

// ── estado local ──────────────────────────────────────────────────────────────
const record = ref(null); // financial_record vinculado
const fetching = ref(false);
const generating = ref(false);
const emittingRecibo = ref(false);

// ── opções de método de pagamento ─────────────────────────────────────────────
const PAYMENT_METHODS = [
    { label: 'Pix', value: 'pix' },
    { label: 'Depósito', value: 'deposito' },
    { label: 'Dinheiro', value: 'dinheiro' },
    { label: 'Cartão', value: 'cartao' },
    { label: 'Convênio', value: 'convenio' }
];

function paymentLabel(method) {
    return PAYMENT_METHODS.find((o) => o.value === method)?.label ?? method ?? '—';
}

// ── formatação ─────────────────────────────────────────────────────────────────
const _brl = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });
function fmtBRL(v) {
    return _brl.format(v ?? 0);
}
function fmtDate(iso) {
    if (!iso) return '—';
    const d = iso.includes('T') ? new Date(iso) : new Date(iso + 'T00:00:00');
    return new Intl.DateTimeFormat('pt-BR').format(d);
}

// ── config visual de status ────────────────────────────────────────────────────
const STATUS_CFG = {
    pending: { label: 'Pendente', severity: 'warn' },
    paid: { label: 'Pago', severity: 'success' },
    overdue: { label: 'Vencido', severity: 'danger' },
    cancelled: { label: 'Cancelado', severity: 'secondary' }
};

// ── computed: cenário a renderizar ────────────────────────────────────────────
const scenario = computed(() => {
    if (props.evento.tipo !== 'sessao') return 'noop'; // bloqueio
    if (props.evento.billing_contract_id) return 'contrato'; // pacote
    if (fetching.value) return 'carregando';
    if (record.value) return 'com-cobranca';
    return 'sem-cobranca';
});

const canAct = computed(() => record.value && (record.value.status === 'pending' || record.value.status === 'overdue'));

// Sessão encerrada (não rolou) — bloqueia geração de cobrança nova.
// Multa em cancelado/faltou deve passar pelo AgendaStatusChangeConfirmDialog,
// não por "Gerar cobrança" solto que ignora o motivo.
const isSessaoEncerrada = computed(() => {
    const s = String(props.evento?.status || '').toLowerCase();
    return s === 'cancelado' || s === 'cancelada' || s === 'faltou';
});
const semCobrancaLabel = computed(() => {
    const s = String(props.evento?.status || '').toLowerCase();
    if (s === 'cancelado' || s === 'cancelada') return 'Sessão cancelada · sem cobrança ativa';
    if (s === 'faltou') return 'Sessão não realizada · sem cobrança ativa';
    return 'Sem cobrança gerada';
});

// ── buscar financial_record pelo evento ───────────────────────────────────────
async function fetchRecord() {
    if (!props.evento.id) return;

    fetching.value = true;
    try {
        // Ignora records cancelados — permite que o user gere nova cobrança
        // após cancelar (caso comum: cancelou sem querer ou quer recobrar).
        // Sem esse filtro, o scenario ficava em 'com-cobranca' mostrando
        // o cancelado, e o botão "Gerar cobrança" sumia.
        const { data, error } = await tenantDb().from('financial_records')
            .select('id, amount, discount_amount, final_amount, status, due_date, paid_at, payment_method')
            .eq('agenda_evento_id', props.evento.id)
            .neq('status', 'cancelled')
            .order('created_at', { ascending: false })
            .limit(1)
            .maybeSingle();

        if (error) throw error;
        record.value = data ?? null;
    } catch (e) {
        console.warn('[AgendaEventoFinanceiroPanel] fetchRecord:', e?.message);
        record.value = null;
    } finally {
        fetching.value = false;
    }
}

watch(
    () => props.evento?.id,
    () => {
        record.value = null;
        fetchRecord();
    },
    { immediate: true }
);

// ── gerar cobrança ─────────────────────────────────────────────────────────────
async function onGerarCobranca() {
    generating.value = true;
    try {
        const result = await gerarCobrancaManual(props.evento);
        if (!result.ok) throw new Error(result.error);

        await fetchRecord();
        emit('cobranca-atualizada');
        toast.add({ severity: 'success', summary: 'Cobrança gerada', detail: `${fmtBRL(props.evento.price ?? 0)} agendado para recebimento.`, life: 3000 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Não foi possível gerar a cobrança.', life: 4000 });
    } finally {
        generating.value = false;
    }
}

// ── dialog: registrar pagamento ───────────────────────────────────────────────
const payDlgVisible = ref(false);
const payDlgMethod = ref(null);
const payDlgLoading = ref(false);

function openPayDialog() {
    payDlgMethod.value = null;
    payDlgVisible.value = true;
}

async function confirmPayment() {
    if (!payDlgMethod.value || !record.value) return;
    payDlgLoading.value = true;
    try {
        const { data, error } = await supabase.rpc('mark_as_paid', {
            p_tenant_id: tenantStore.activeTenantId,
            p_financial_record_id: record.value.id,
            p_payment_method: payDlgMethod.value
        });
        if (error) throw error;

        payDlgVisible.value = false;
        await fetchRecord();
        emit('cobranca-atualizada');
        toast.add({ severity: 'success', summary: 'Pago!', detail: `Recebimento via ${paymentLabel(payDlgMethod.value)} registrado.`, life: 3000 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Não foi possível registrar pagamento.', life: 4000 });
    } finally {
        payDlgLoading.value = false;
    }
}

// ── cancelar cobrança ─────────────────────────────────────────────────────────
function requestCancel() {
    confirm.require({
        message: `Cancelar a cobrança de ${fmtBRL(record.value?.final_amount)} desta sessão?`,
        header: 'Cancelar cobrança',
        icon: 'pi pi-exclamation-triangle',
        rejectLabel: 'Não',
        acceptLabel: 'Sim, cancelar',
        acceptSeverity: 'danger',
        accept: async () => {
            try {
                const { error } = await tenantDb().from('financial_records').update({ status: 'cancelled', updated_at: new Date().toISOString() }).eq('id', record.value.id);

                if (error) throw error;

                await fetchRecord();
                emit('cobranca-atualizada');
                toast.add({ severity: 'info', summary: 'Cancelado', detail: 'Cobrança cancelada.', life: 3000 });
            } catch (e) {
                toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao cancelar.', life: 4000 });
            }
        }
    });
}

// ── Emitir recibo PDF da sessão ─────────────────────────────────────────────
// Gera, salva (Storage + documents/document_generated) e baixa um recibo
// pré-preenchido com paciente/sessão/valor/forma de pagamento + registro
// profissional do terapeuta (CRP/CRM/CRFa etc — auto-formatado).
async function onEmitirRecibo() {
    if (emittingRecibo.value) return;
    emittingRecibo.value = true;
    try {
        await emitirReciboParaSessao(props.evento.id, {
            patientId: props.evento.patient_id || props.evento.paciente_id,
            valor: record.value?.final_amount ?? record.value?.amount ?? props.evento.price,
            formaPagamento: paymentLabel(record.value?.payment_method)
        });
        toast.add({ severity: 'success', summary: 'Recibo emitido', detail: 'PDF baixado e salvo nos documentos do paciente.', life: 3000 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao emitir recibo', detail: e?.message || 'Tente novamente.', life: 4500 });
    } finally {
        emittingRecibo.value = false;
    }
}
</script>

<template>
    <div>
        <!-- Painel principal — noop (bloqueios) não renderiza nada -->
        <div v-if="scenario !== 'noop'" class="fin-panel">
            <!-- Cabeçalho do painel -->
            <div class="fin-panel__header">
                <i class="pi pi-wallet" />
                <span>Cobrança</span>
                <Button v-if="props.evento.billed && !fetching" icon="pi pi-refresh" text size="small" severity="secondary" class="ml-auto h-6 w-6" v-tooltip.top="'Recarregar'" @click="fetchRecord" />
            </div>

            <!-- ── Sessão de pacote / contrato ──────────────────────────────────── -->
            <div v-if="scenario === 'contrato'" class="fin-panel__body">
                <span class="fin-badge fin-badge--contract">
                    <i class="pi pi-box text-xs" />
                    Sessão de pacote
                </span>
            </div>

            <!-- ── Sem cobrança gerada ──────────────────────────────────────────── -->
            <div v-else-if="scenario === 'sem-cobranca'" class="fin-panel__body fin-panel__body--empty">
                <div class="flex items-center gap-2 text-[var(--text-color-secondary)]">
                    <i class="pi pi-minus-circle text-sm opacity-50" />
                    <span class="text-sm">{{ semCobrancaLabel }}</span>
                </div>
                <!-- Botão "Gerar cobrança" só aparece em status ativo (agendado/realizado).
                     Pra cancelado/faltou: sessão não aconteceu → cobrança nova não cabe
                     aqui. Pra registrar multa, usar o dialog de status change. -->
                <Button v-if="!isSessaoEncerrada" label="Gerar cobrança" icon="pi pi-plus" size="small" class="rounded-full mt-2" :loading="generating || finLoading" @click="onGerarCobranca" />
                <div v-if="props.evento.price && !isSessaoEncerrada" class="text-xs text-[var(--text-color-secondary)] mt-1">Valor da sessão: {{ fmtBRL(props.evento.price) }}</div>
            </div>

            <!-- ── Carregando o financial_record ────────────────────────────────── -->
            <div v-else-if="scenario === 'carregando'" class="fin-panel__body">
                <div class="flex flex-col gap-1.5">
                    <Skeleton height="1rem" class="w-24" />
                    <Skeleton height="1.5rem" class="w-32" />
                    <Skeleton height="1rem" class="w-20" />
                </div>
            </div>

            <!-- ── Com cobrança ─────────────────────────────────────────────────── -->
            <div v-else-if="scenario === 'com-cobranca'" class="fin-panel__body">
                <!-- Linha de status + valor -->
                <div class="flex items-center justify-between gap-2">
                    <Tag :value="STATUS_CFG[record.status]?.label ?? record.status" :severity="STATUS_CFG[record.status]?.severity" class="text-xs" />
                    <span class="font-bold text-sm text-[var(--text-color)]">{{ fmtBRL(record.final_amount) }}</span>
                </div>

                <!-- Vencimento / data de pagamento -->
                <div class="flex items-center gap-1.5 text-xs text-[var(--text-color-secondary)] mt-1.5">
                    <template v-if="record.status === 'paid'">
                        <i class="pi pi-check-circle text-emerald-500" />
                        <span class="text-emerald-600">{{ paymentLabel(record.payment_method) }} · {{ fmtDate(record.paid_at) }}</span>
                    </template>
                    <template v-else>
                        <i class="pi pi-calendar" />
                        <span :class="record.status === 'overdue' ? 'text-red-500 font-semibold' : ''"> Vence {{ fmtDate(record.due_date) }} </span>
                    </template>
                </div>

                <!-- Ações: pendente / vencido -->
                <div v-if="canAct" class="flex gap-1.5 mt-3">
                    <Button label="Receber" icon="pi pi-check" size="small" class="rounded-full flex-1" @click="openPayDialog" />
                    <Button icon="pi pi-times" size="small" severity="danger" outlined class="rounded-full h-7 w-7" v-tooltip.top="'Cancelar cobrança'" @click="requestCancel" />
                </div>

                <!-- Ação: pago — emitir recibo PDF -->
                <div v-else-if="record.status === 'paid'" class="flex gap-1.5 mt-3">
                    <Button
                        label="Emitir recibo"
                        icon="pi pi-file-pdf"
                        size="small"
                        outlined
                        class="rounded-full flex-1"
                        :loading="emittingRecibo"
                        v-tooltip.top="'Gera PDF e salva nos documentos do paciente'"
                        @click="onEmitirRecibo"
                    />
                </div>
            </div>
        </div>

        <!-- ── Dialog: Registrar Pagamento ──────────────────────────────────────── -->
        <Dialog v-model:visible="payDlgVisible" modal :draggable="false" pt:mask:class="backdrop-blur-xs" header="Registrar pagamento" class="w-[92vw] max-w-sm">
            <div class="flex flex-col gap-4 pt-1">
                <!-- Valor -->
                <div class="flex items-center justify-between px-4 py-2.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)]">
                    <span class="text-sm text-[var(--text-color-secondary)]">Valor a receber</span>
                    <span class="font-bold text-[var(--text-color)]">{{ fmtBRL(record?.final_amount) }}</span>
                </div>

                <!-- Método (grid de botões) -->
                <div>
                    <div class="text-sm font-semibold text-[var(--text-color)] mb-2">Método de pagamento</div>
                    <div class="grid grid-cols-3 gap-2">
                        <button
                            v-for="opt in PAYMENT_METHODS"
                            :key="opt.value"
                            type="button"
                            class="flex flex-col items-center gap-1 px-2 py-2 rounded-md border text-xs font-medium transition-all duration-150 cursor-pointer select-none"
                            :class="
                                payDlgMethod === opt.value
                                    ? 'border-[var(--primary-color,#6366f1)] bg-[var(--primary-color,#6366f1)]/10 text-[var(--primary-color,#6366f1)]'
                                    : 'border-[var(--surface-border)] bg-[var(--surface-ground)] text-[var(--text-color-secondary)] hover:border-[var(--primary-color,#6366f1)]/40'
                            "
                            @click="payDlgMethod = opt.value"
                        >
                            <i
                                class="text-base"
                                :class="{
                                    'pi pi-bolt': opt.value === 'pix',
                                    'pi pi-building': opt.value === 'deposito',
                                    'pi pi-money-bill': opt.value === 'dinheiro',
                                    'pi pi-credit-card': opt.value === 'cartao',
                                    'pi pi-id-card': opt.value === 'convenio'
                                }"
                            />
                            {{ opt.label }}
                        </button>
                    </div>
                </div>
            </div>

            <template #footer>
                <Button label="Cancelar" severity="secondary" outlined class="rounded-full" :disabled="payDlgLoading" @click="payDlgVisible = false" />
                <Button label="Confirmar" icon="pi pi-check" class="rounded-full" :loading="payDlgLoading" :disabled="!payDlgMethod" @click="confirmPayment" />
            </template>
        </Dialog>
    </div>
</template>

<style scoped>
.fin-panel {
    border: 1px solid var(--surface-border, #e2e8f0);
    border-radius: 0.5rem;
    overflow: hidden;
    background: var(--surface-card, #fff);
}

.fin-panel__header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: var(--surface-ground, #f8fafc);
    border-bottom: 1px solid var(--surface-border, #e2e8f0);
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-color-secondary);
}

.fin-panel__body {
    padding: 0.75rem;
}

.fin-panel__body--empty {
    display: flex;
    flex-direction: column;
}

.fin-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.25rem 0.625rem;
    border-radius: 9999px;
}

.fin-badge--contract {
    background: color-mix(in srgb, var(--p-indigo-500, #6366f1) 10%, transparent);
    color: var(--p-indigo-600, #4f46e5);
    border: 1px solid color-mix(in srgb, var(--p-indigo-500, #6366f1) 20%, transparent);
}
</style>
