/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Arquivo: src/composables/useContactPhones.js
| Data: 2026-04-21
|
| Gerenciamento polimórfico de telefones (patients, medicos, etc).
|--------------------------------------------------------------------------
*/

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

function normalizeDigits(raw) {
    return String(raw || '').replace(/\D/g, '');
}

// Telefones em "modo pendente" (entidade ainda não existe no DB) usam ID
// com este prefixo. Permite reusar o mesmo array `phones` na UI sem
// sub-state e detectar quais precisam de INSERT no flushPending.
const PENDING_PREFIX = 'pending_';
function isPending(id) { return typeof id === 'string' && id.startsWith(PENDING_PREFIX); }
function genPendingId() {
    return `${PENDING_PREFIX}${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
}

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

    const types = ref([]);        // contact_types (system + custom do tenant)
    const phones = ref([]);       // contact_phones da entidade atual
    const loading = ref(false);
    const saving = ref(false);

    async function loadTypes() {
        try {
            const { data } = await tenantDb().from('contact_types')
                .select('id, name, slug, icon, is_mobile, is_system, position')
                .order('position', { ascending: true })
                .order('name', { ascending: true });
            types.value = data || [];
        } catch (e) {
            console.error('[useContactPhones] loadTypes:', e?.message);
            types.value = [];
        }
    }

    async function loadPhones(entityType, entityId) {
        if (!entityType || !entityId) {
            phones.value = [];
            return;
        }
        loading.value = true;
        try {
            const { data, error } = await tenantDb().from('contact_phones')
                .select('id, contact_type_id, number, is_primary, whatsapp_linked_at, notes, position, created_at')
                .eq('entity_type', entityType)
                .eq('entity_id', entityId)
                .order('is_primary', { ascending: false })
                .order('position', { ascending: true });
            if (error) throw error;
            phones.value = data || [];
        } catch (e) {
            console.error('[useContactPhones] loadPhones:', e?.message);
            phones.value = [];
        } finally {
            loading.value = false;
        }
    }

    // Ensure só 1 primary por entidade — seta outros pra false antes de inserir/atualizar
    async function unsetOtherPrimaries(entityType, entityId, exceptId = null) {
        const q = tenantDb().from('contact_phones')
            .update({ is_primary: false })
            .eq('entity_type', entityType)
            .eq('entity_id', entityId)
            .eq('is_primary', true);
        if (exceptId) q.neq('id', exceptId);
        await q;
    }

    async function addPhone(entityType, entityId, { contact_type_id, number, is_primary = false, whatsapp_linked_at = null, notes = null }) {
        const digits = normalizeDigits(number);
        if (!contact_type_id) return { ok: false, error: 'Tipo de contato obrigatório' };
        if (!digits || digits.length < 8 || digits.length > 15) return { ok: false, error: 'Telefone inválido' };

        // Modo pendente: entidade ainda não existe (ex: novo paciente sendo
        // cadastrado). Mantém em memória — flushPending grava tudo em lote
        // depois que a entidade for criada.
        if (!entityType || !entityId) {
            const wasFirst = phones.value.length === 0;
            if (is_primary || wasFirst) {
                phones.value.forEach((p) => { p.is_primary = false; });
                is_primary = true;
            }
            const maxPos = phones.value.reduce((m, p) => Math.max(m, p.position || 0), 0);
            const tempPhone = {
                id: genPendingId(),
                contact_type_id,
                number: digits,
                is_primary,
                whatsapp_linked_at,
                notes,
                position: maxPos + 10,
                created_at: new Date().toISOString()
            };
            phones.value = [...phones.value, tempPhone];
            return { ok: true, phone: tempPhone };
        }

        const tenantId = tenantStore.activeTenantId;
        if (!tenantId) return { ok: false, error: 'invalid_context' };

        saving.value = true;
        try {
            // Se marcou como primary, desmarca outros
            if (is_primary) {
                await unsetOtherPrimaries(entityType, entityId);
            } else if (phones.value.length === 0) {
                // Primeiro telefone → vira primary automaticamente
                is_primary = true;
            }

            const maxPos = phones.value.reduce((m, p) => Math.max(m, p.position || 0), 0);
            const { data, error } = await tenantDb().from('contact_phones')
                .insert({
                    entity_type: entityType,
                    entity_id: entityId,
                    contact_type_id,
                    number: digits,
                    is_primary,
                    whatsapp_linked_at,
                    notes,
                    position: maxPos + 10
                })
                .select()
                .single();
            if (error) throw error;
            await loadPhones(entityType, entityId);
            return { ok: true, phone: data };
        } catch (e) {
            return { ok: false, error: e?.message || 'add_failed' };
        } finally {
            saving.value = false;
        }
    }

    async function updatePhone(entityType, entityId, id, patch) {
        const sanitized = { ...patch };
        if (sanitized.number !== undefined) sanitized.number = normalizeDigits(sanitized.number);
        if (sanitized.number && (sanitized.number.length < 8 || sanitized.number.length > 15)) {
            return { ok: false, error: 'Telefone inválido' };
        }

        // Pending: muta no array local sem ir pro DB
        if (isPending(id) || !entityType || !entityId) {
            const idx = phones.value.findIndex((p) => p.id === id);
            if (idx === -1) return { ok: false, error: 'not_found' };
            if (sanitized.is_primary === true) {
                phones.value.forEach((p, i) => { if (i !== idx) p.is_primary = false; });
            }
            phones.value[idx] = { ...phones.value[idx], ...sanitized };
            phones.value = [...phones.value];
            return { ok: true };
        }

        saving.value = true;
        try {
            if (sanitized.is_primary === true) {
                await unsetOtherPrimaries(entityType, entityId, id);
            }

            const { error } = await tenantDb().from('contact_phones')
                .update(sanitized)
                .eq('id', id);
            if (error) throw error;
            await loadPhones(entityType, entityId);
            return { ok: true };
        } catch (e) {
            return { ok: false, error: e?.message || 'update_failed' };
        } finally {
            saving.value = false;
        }
    }

    async function removePhone(entityType, entityId, id) {
        // Pending: tira do array local + promove o próximo a primary se sumiu
        if (isPending(id) || !entityType || !entityId) {
            const wasPrimary = phones.value.find((p) => p.id === id)?.is_primary;
            phones.value = phones.value.filter((p) => p.id !== id);
            if (wasPrimary && phones.value.length > 0) {
                const remaining = [...phones.value].sort((a, b) => (a.position || 0) - (b.position || 0));
                phones.value = phones.value.map((p) =>
                    p.id === remaining[0].id ? { ...p, is_primary: true } : p
                );
            }
            return { ok: true };
        }

        saving.value = true;
        try {
            const wasPrimary = phones.value.find((p) => p.id === id)?.is_primary;
            const { error } = await tenantDb().from('contact_phones').delete().eq('id', id);
            if (error) throw error;

            // Se removeu o primary, promove o próximo pra primary
            if (wasPrimary) {
                const remaining = phones.value.filter((p) => p.id !== id).sort((a, b) => (a.position || 0) - (b.position || 0));
                if (remaining.length > 0) {
                    await tenantDb().from('contact_phones')
                        .update({ is_primary: true })
                        .eq('id', remaining[0].id);
                }
            }
            await loadPhones(entityType, entityId);
            return { ok: true };
        } catch (e) {
            return { ok: false, error: e?.message || 'remove_failed' };
        } finally {
            saving.value = false;
        }
    }

    // Grava em lote os telefones que estavam em modo pendente. Chamado pelo
    // parent (ex: PatientsCadastroPage) logo depois de criar a entidade no DB.
    // Mantém ordem (position) e o flag is_primary do estado local.
    async function flushPending(entityType, entityId) {
        if (!entityType || !entityId) return { ok: false, error: 'missing_entity' };
        const tenantId = tenantStore.activeTenantId;
        if (!tenantId) return { ok: false, error: 'invalid_context' };
        const pendingItems = phones.value.filter((p) => isPending(p.id));
        if (pendingItems.length === 0) return { ok: true, count: 0 };
        saving.value = true;
        try {
            const rows = pendingItems.map((p) => ({
                entity_type: entityType,
                entity_id: entityId,
                contact_type_id: p.contact_type_id,
                number: normalizeDigits(p.number),
                is_primary: !!p.is_primary,
                whatsapp_linked_at: p.whatsapp_linked_at || null,
                notes: p.notes || null,
                position: p.position
            }));
            const { error } = await tenantDb().from('contact_phones').insert(rows);
            if (error) throw error;
            // Recarrega do DB pra ter IDs reais — substitui os pending_* por uuids.
            await loadPhones(entityType, entityId);
            return { ok: true, count: rows.length };
        } catch (e) {
            return { ok: false, error: e?.message || 'flush_failed' };
        } finally {
            saving.value = false;
        }
    }

    async function setPrimary(entityType, entityId, id) {
        return updatePhone(entityType, entityId, id, { is_primary: true });
    }

    function typeBySlug(slug) {
        return types.value.find((t) => t.slug === slug);
    }
    function typeById(id) {
        return types.value.find((t) => t.id === id);
    }

    return {
        types,
        phones,
        loading,
        saving,
        loadTypes,
        loadPhones,
        addPhone,
        updatePhone,
        removePhone,
        setPrimary,
        flushPending,
        typeBySlug,
        typeById
    };
}
