/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/composables/useFinancialRecords.js
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
*/

import { ref, computed } from 'vue';
import { supabase } from '@/lib/supabase/client';
import { tenantDb } from '@/lib/supabase/tenantClient';
import { useTenantStore } from '@/stores/tenantStore';

// ─── helpers internos ────────────────────────────────────────────────────────

function assertTenantId(tenantId) {
    if (!tenantId || tenantId === 'null' || tenantId === 'undefined') {
        throw new Error('Tenant ativo inválido. Selecione a clínica antes de operar no financeiro.');
    }
}

async function getUid() {
    const { data, error } = await supabase.auth.getUser();
    if (error) throw error;
    const uid = data?.user?.id;
    if (!uid) throw new Error('Usuário não autenticado.');
    return uid;
}

// ─── select base com joins ───────────────────────────────────────────────────

const BASE_SELECT = `
  id, owner_id, patient_id, agenda_evento_id,
  type, amount, discount_amount, final_amount,
  status, due_date, paid_at, payment_method, payment_link,
  description, notes, created_at, updated_at,
  patients!patient_id (
    id, nome_completo, identification_color
  ),
  agenda_eventos!agenda_evento_id (
    id, inicio_em, status, tipo
  )
`.trim();

// ─── composable ──────────────────────────────────────────────────────────────

export function useFinancialRecords() {
    const records = ref([]);
    const loading = ref(false);
    const error = ref(null);

    // ── computed: resumo financeiro ─────────────────────────────────────────

    const summary = computed(() => {
        const now = new Date();
        const thisYear = now.getFullYear();
        const thisMonth = now.getMonth(); // 0-indexed

        const countByStatus = { pending: 0, paid: 0, overdue: 0, cancelled: 0 };

        let totalPending = 0;
        let totalOverdue = 0;
        let totalPaidThisMonth = 0;

        for (const r of records.value) {
            countByStatus[r.status] = (countByStatus[r.status] ?? 0) + 1;

            if (r.status === 'pending') {
                totalPending += r.final_amount ?? r.amount ?? 0;
            }

            if (r.status === 'overdue') {
                totalOverdue += r.final_amount ?? r.amount ?? 0;
            }

            if (r.status === 'paid' && r.paid_at) {
                const d = new Date(r.paid_at);
                if (d.getFullYear() === thisYear && d.getMonth() === thisMonth) {
                    totalPaidThisMonth += r.final_amount ?? r.amount ?? 0;
                }
            }
        }

        return { totalPending, totalOverdue, totalPaidThisMonth, countByStatus };
    });

    // ── fetchRecords ─────────────────────────────────────────────────────────

    /**
     * @param {Object} [filters]
     * @param {string}   [filters.status]          - 'pending'|'paid'|'overdue'|'partial'|'cancelled'|'refunded'
     * @param {string}   [filters.type]            - 'receita'|'despesa'
     * @param {string}   [filters.patient_id]      - UUID
     * @param {string}   [filters.due_date_from]   - ISO date string
     * @param {string}   [filters.due_date_to]     - ISO date string
     * @param {number}   [filters.limit]           - rows per page (default 50)
     * @param {number}   [filters.offset]          - row offset for pagination (default 0)
     * @returns {Promise<{total: number}>}
     */
    async function fetchRecords(filters = {}) {
        const tenantStore = useTenantStore();
        const tenantId = tenantStore.activeTenantId;
        assertTenantId(tenantId);

        loading.value = true;
        error.value = null;

        const limit = filters.limit ?? 50;
        const offset = filters.offset ?? 0;

        try {
            let query = tenantDb().from('financial_records')
                .select(BASE_SELECT, { count: 'exact' })
                .is('deleted_at', null)
                .order('due_date', { ascending: false })
                .range(offset, offset + limit - 1);

            if (filters.status) query = query.eq('status', filters.status);
            if (filters.type) query = query.eq('type', filters.type);
            if (filters.patient_id) query = query.eq('patient_id', filters.patient_id);
            if (filters.due_date_from) query = query.gte('due_date', filters.due_date_from);
            if (filters.due_date_to) query = query.lte('due_date', filters.due_date_to);

            const { data, error: err, count } = await query;
            if (err) throw err;

            records.value = data ?? [];
            return { total: count ?? 0 };
        } catch (e) {
            error.value = e?.message || 'Erro ao carregar registros financeiros.';
            records.value = [];
            return { total: 0 };
        } finally {
            loading.value = false;
        }
    }

    // ── createRecord (via RPC — para sessões) ────────────────────────────────

    /**
     * @param {Object} payload
     * @param {string}  payload.patient_id
     * @param {string}  payload.agenda_evento_id
     * @param {number}  payload.amount
     * @param {string}  payload.due_date  - ISO date string
     */
    async function createRecord(payload) {
        const tenantStore = useTenantStore();
        const tenantId = tenantStore.activeTenantId;
        assertTenantId(tenantId);

        const ownerId = await getUid();

        loading.value = true;
        error.value = null;

        try {
            const { data, error: err } = await supabase.rpc('create_financial_record_for_session', {
                p_tenant_id: tenantId,
                p_owner_id: ownerId,
                p_patient_id: payload.patient_id,
                p_agenda_evento_id: payload.agenda_evento_id,
                p_amount: payload.amount,
                p_due_date: payload.due_date
            });

            if (err) throw err;

            // Re-fetch para garantir joins completos
            await fetchRecords();

            return { ok: true, data };
        } catch (e) {
            error.value = e?.message || 'Erro ao criar cobrança.';
            return { ok: false, error: e?.message };
        } finally {
            loading.value = false;
        }
    }

    // ── createManualRecord (INSERT direto — sem sessão) ──────────────────────

    /**
     * @param {Object} payload
     * @param {string}   payload.patient_id
     * @param {number}   payload.amount
     * @param {number}   [payload.discount_amount]
     * @param {string}   payload.due_date
     * @param {string}   [payload.status]           - default 'pending'
     * @param {string}   [payload.payment_method]
     * @param {string}   [payload.notes]
     */
    async function createManualRecord(payload) {
        const tenantStore = useTenantStore();
        const tenantId = tenantStore.activeTenantId;
        assertTenantId(tenantId);

        const ownerId = await getUid();

        loading.value = true;
        error.value = null;

        try {
            const discount = payload.discount_amount ?? 0;
            const amount = payload.amount ?? 0;

            const { data, error: err } = await tenantDb().from('financial_records')
                .insert([
                    {
                        owner_id: ownerId,
                        patient_id: payload.patient_id ?? null,
                        agenda_evento_id: null,
                        amount,
                        discount_amount: discount,
                        final_amount: amount - discount,
                        status: payload.status ?? 'pending',
                        due_date: payload.due_date,
                        payment_method: payload.payment_method ?? null,
                        notes: payload.notes ?? null
                    }
                ])
                .select(BASE_SELECT)
                .single();

            if (err) throw err;

            records.value = [data, ...records.value];

            return { ok: true, data };
        } catch (e) {
            error.value = e?.message || 'Erro ao criar lançamento manual.';
            return { ok: false, error: e?.message };
        } finally {
            loading.value = false;
        }
    }

    // ── markAsPaid ───────────────────────────────────────────────────────────

    /**
     * @param {string} recordId
     * @param {string} paymentMethod - 'pix' | 'deposito' | 'dinheiro' | 'cartao' | 'convenio'
     */
    async function markAsPaid(recordId, paymentMethod) {
        error.value = null;

        try {
            const tenantStore = useTenantStore();
            const tenantId = tenantStore.activeTenantId;
            assertTenantId(tenantId);

            const { data, error: err } = await supabase.rpc('mark_as_paid', {
                p_tenant_id: tenantId,
                p_financial_record_id: recordId,
                p_payment_method: paymentMethod
            });

            if (err) throw err;

            // RPC retorna jsonb (objeto único) — patch local direto, sem depender do retorno
            const idx = records.value.findIndex((r) => r.id === recordId);
            if (idx !== -1) {
                records.value[idx] = {
                    ...records.value[idx],
                    status: 'paid',
                    paid_at: new Date().toISOString(),
                    payment_method: paymentMethod
                };
            }

            return { ok: true };
        } catch (e) {
            error.value = e?.message || 'Erro ao marcar como pago.';
            return { ok: false, error: e?.message };
        }
    }

    // ── cancelRecord ─────────────────────────────────────────────────────────

    /**
     * @param {string} recordId
     */
    async function cancelRecord(recordId) {
        error.value = null;

        try {
            const { error: err } = await tenantDb().from('financial_records').update({ status: 'cancelled', updated_at: new Date().toISOString() }).eq('id', recordId);

            if (err) throw err;

            // Atualiza localmente sem re-fetch
            const idx = records.value.findIndex((r) => r.id === recordId);
            if (idx !== -1) {
                records.value[idx] = { ...records.value[idx], status: 'cancelled' };
            }

            return { ok: true };
        } catch (e) {
            error.value = e?.message || 'Erro ao cancelar registro.';
            return { ok: false, error: e?.message };
        }
    }

    // ─────────────────────────────────────────────────────────────────────────

    return {
        // estado
        records,
        loading,
        error,
        // computed
        summary,
        // ações
        fetchRecords,
        createRecord,
        createManualRecord,
        markAsPaid,
        cancelRecord
    };
}
