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

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

// Metadata canonica das colunas do kanban — fonte unica consumida pelo
// SFC parent (kanban grid central) e pelo MelissaConversasSidebar
// (resumo "Por status"). Antes, parent + sidebar tinham copias locais
// de KANBAN_COLUMNS e o composable separadamente tinha KANBAN_ORDER.
export const KANBAN_COLUMNS = Object.freeze([
    Object.freeze({ key: 'urgent', label: 'Urgente', icon: 'pi pi-exclamation-triangle', color: 'red' }),
    Object.freeze({ key: 'awaiting_us', label: 'Aguardando resposta', icon: 'pi pi-inbox', color: 'amber' }),
    Object.freeze({ key: 'awaiting_patient', label: 'Aguardando paciente', icon: 'pi pi-hourglass', color: 'blue' }),
    Object.freeze({ key: 'resolved', label: 'Resolvido', icon: 'pi pi-check', color: 'emerald' })
]);
const KANBAN_ORDER = KANBAN_COLUMNS.map((c) => c.key);

function sanitizeSearch(raw) {
    if (typeof raw !== 'string') return '';
    return raw.trim().slice(0, 120).toLowerCase();
}

export function useConversations() {
    const tenantStore = useTenantStore();

    const threads = ref([]);
    const loading = ref(false);
    const error = ref(null);

    const filters = ref({
        search: '',
        channel: null, // null = todos
        unreadOnly: false,
        assigned: null // null = todas | 'me' | 'unassigned' | <uuid>
    });

    const currentUserId = ref(null);
    supabase.auth.getUser().then(({ data }) => { currentUserId.value = data?.user?.id ?? null; });

    let realtimeChannel = null;

    // Debounce do refetch disparado por realtime — sem isso, clínica ativa
    // recebendo 10 mensagens/min faz 10 SELECT 500 na lista de threads por
    // minuto. 300ms agrupa rajadas (digita-rápido, mensagens em sequência)
    // sem fazer o user esperar visualmente. A nova mensagem em si vai pro
    // threadMessages direto (acima); load() é só pra atualizar contadores
    // e preview do thread na lista — pode esperar.
    let _loadDebounceTimer = null;
    function _scheduleLoad() {
        if (_loadDebounceTimer) clearTimeout(_loadDebounceTimer);
        _loadDebounceTimer = setTimeout(() => {
            _loadDebounceTimer = null;
            load();
        }, 300);
    }

    async function load() {
        const tenantId = tenantStore.activeTenantId;
        if (!tenantId) {
            threads.value = [];
            error.value = new Error('Tenant ativo inválido');
            return;
        }

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

        try {
            const { data, error: qErr } = await tenantDb().from('conversation_threads')
                .select('*')
                .order('last_message_at', { ascending: false })
                .limit(500);
            if (qErr) throw qErr;
            threads.value = data ?? [];
        } catch (err) {
            error.value = err;
            threads.value = [];
        } finally {
            loading.value = false;
        }
    }

    function subscribeRealtime() {
        const tenantId = tenantStore.activeTenantId;
        const tenantSchema = tenantStore.activeTenantSchema;
        if (!tenantId || !tenantSchema) return;
        if (realtimeChannel) {
            supabase.removeChannel(realtimeChannel);
        }
        realtimeChannel = supabase
            .channel(`conv_msg_tenant_${tenantId}`)
            .on(
                'postgres_changes',
                {
                    event: 'INSERT',
                    schema: tenantSchema,
                    table: 'conversation_messages'
                },
                (payload) => {
                    // refetch da lista (view agrega tudo) — debounced
                    _scheduleLoad();
                    // se o drawer esta aberto numa thread desta msg, appenda
                    const newMsg = payload.new;
                    if (currentThread.value && messageBelongsToThread(newMsg, currentThread.value)) {
                        const alreadyThere = threadMessages.value.some((m) => m.id === newMsg.id);
                        if (!alreadyThere) threadMessages.value.push(newMsg);
                    }
                }
            )
            .on(
                'postgres_changes',
                {
                    event: 'UPDATE',
                    schema: tenantSchema,
                    table: 'conversation_messages'
                },
                (payload) => {
                    _scheduleLoad();
                    const updated = payload.new;
                    if (currentThread.value && messageBelongsToThread(updated, currentThread.value)) {
                        const idx = threadMessages.value.findIndex((m) => m.id === updated.id);
                        if (idx >= 0) threadMessages.value[idx] = updated;
                    }
                }
            )
            .subscribe();
    }

    function unsubscribeRealtime() {
        if (realtimeChannel) {
            supabase.removeChannel(realtimeChannel);
            realtimeChannel = null;
        }
        // Cancela refetch agendado — se desmontar entre o trigger e o
        // debounce dispara, callback rodaria em ref morta.
        if (_loadDebounceTimer) {
            clearTimeout(_loadDebounceTimer);
            _loadDebounceTimer = null;
        }
    }

    onUnmounted(() => unsubscribeRealtime());

    const filteredThreads = computed(() => {
        const q = sanitizeSearch(filters.value.search);
        const assignFilter = filters.value.assigned;
        const uid = currentUserId.value;
        return threads.value.filter((t) => {
            if (filters.value.channel && t.channel !== filters.value.channel) return false;
            if (filters.value.unreadOnly && (t.unread_count || 0) === 0) return false;
            if (assignFilter === 'me') {
                if (!uid || t.assigned_to !== uid) return false;
            } else if (assignFilter === 'unassigned') {
                if (t.assigned_to) return false;
            } else if (assignFilter && typeof assignFilter === 'string') {
                if (t.assigned_to !== assignFilter) return false;
            }
            if (q) {
                const name = (t.patient_name || '').toLowerCase();
                const num = (t.contact_number || '').toLowerCase();
                const body = (t.last_message_body || '').toLowerCase();
                if (!name.includes(q) && !num.includes(q) && !body.includes(q)) return false;
            }
            return true;
        });
    });

    const byKanban = computed(() => {
        const map = { urgent: [], awaiting_us: [], awaiting_patient: [], resolved: [] };
        for (const t of filteredThreads.value) {
            const k = KANBAN_ORDER.includes(t.kanban_status) ? t.kanban_status : 'awaiting_us';
            map[k].push(t);
        }
        return map;
    });

    const summary = computed(() => ({
        total: threads.value.length,
        urgent: byKanban.value.urgent.length,
        awaiting_us: byKanban.value.awaiting_us.length,
        awaiting_patient: byKanban.value.awaiting_patient.length,
        resolved: byKanban.value.resolved.length,
        unreadTotal: threads.value.reduce((s, t) => s + (t.unread_count || 0), 0)
    }));

    // Mensagens de uma thread especifica (drawer)
    const threadMessages = ref([]);
    const threadLoading = ref(false);
    const currentThread = ref(null);

    function messageBelongsToThread(msg, thread) {
        if (!thread || !msg) return false;
        if (thread.patient_id) return msg.patient_id === thread.patient_id;
        // thread anônima
        if (msg.patient_id) return false;
        return (
            msg.from_number === thread.contact_number ||
            msg.to_number === thread.contact_number
        );
    }

    async function loadThreadMessages(thread) {
        currentThread.value = thread;
        if (!thread) {
            threadMessages.value = [];
            return;
        }
        threadLoading.value = true;
        try {
            let q = tenantDb().from('conversation_messages')
                .select('*')
                .order('created_at', { ascending: true })
                .limit(500);

            if (thread.patient_id) {
                q = q.eq('patient_id', thread.patient_id);
            } else {
                // anônimo — filtra por from_number ou to_number
                q = q.or(`from_number.eq.${thread.contact_number},to_number.eq.${thread.contact_number}`).is('patient_id', null);
            }

            const { data, error: qErr } = await q;
            if (qErr) throw qErr;
            threadMessages.value = data ?? [];
        } finally {
            threadLoading.value = false;
        }
    }

    async function markThreadRead(thread) {
        if (!thread) return;
        // Marca unread do inbound como lido
        const nowIso = new Date().toISOString();
        const tenantId = tenantStore.activeTenantId;
        let q = tenantDb().from('conversation_messages')
            .update({ read_at: nowIso })
            .eq('direction', 'inbound')
            .is('read_at', null);
        if (thread.patient_id) q = q.eq('patient_id', thread.patient_id);
        else q = q.eq('from_number', thread.contact_number).is('patient_id', null);
        await q;
        load();
    }

    async function setKanbanStatus(thread, newStatus) {
        if (!['urgent', 'awaiting_us', 'awaiting_patient', 'resolved'].includes(newStatus)) return;
        const tenantId = tenantStore.activeTenantId;
        const patch = { kanban_status: newStatus };
        if (newStatus === 'resolved') patch.resolved_at = new Date().toISOString();

        let q = tenantDb().from('conversation_messages').update(patch);
        if (thread.patient_id) q = q.eq('patient_id', thread.patient_id);
        else q = q.eq('from_number', thread.contact_number).is('patient_id', null);

        await q;
        load();
    }

    return {
        threads,
        filteredThreads,
        byKanban,
        summary,
        filters,
        loading,
        error,
        load,
        subscribeRealtime,
        unsubscribeRealtime,
        threadMessages,
        threadLoading,
        loadThreadMessages,
        markThreadRead,
        setKanbanStatus,
        // Exposto pra evitar que cada consumidor chame supabase.auth.getUser()
        // por conta propria — antes, MelissaConversas + composable faziam 2
        // round-trips ao auth no mesmo mount.
        currentUserId
    };
}
