import { computed, ref } from 'vue';
import { normalizeNigeriaPhoneNumber } from '@/Utils/nigeriaPhone';

const RECENT_RECIPIENTS_STORAGE_KEY = 'vtu:recipient-recents:v1';
const MAX_RECENT_RECIPIENTS = 30;

const normalizeRecipientEntry = (entry) => {
    if (!entry || typeof entry !== 'object') return null;

    const phone = normalizeNigeriaPhoneNumber(String(entry.phone || ''));
    if (!phone) return null;

    const label = String(entry.label || '').trim();
    const source = String(entry.source || 'manual').trim() || 'manual';
    const createdAt = String(entry.created_at || entry.createdAt || '').trim() || new Date().toISOString();

    return {
        phone,
        label,
        source,
        created_at: createdAt,
    };
};

const loadLocalRecentRecipients = () => {
    if (typeof window === 'undefined') return [];

    try {
        const raw = window.localStorage.getItem(RECENT_RECIPIENTS_STORAGE_KEY);
        if (!raw) return [];
        const parsed = JSON.parse(raw);
        if (!Array.isArray(parsed)) return [];

        return parsed
            .map((entry) => normalizeRecipientEntry(entry))
            .filter((entry) => !!entry);
    } catch {
        return [];
    }
};

const saveLocalRecentRecipients = (recipients) => {
    if (typeof window === 'undefined') return;

    try {
        window.localStorage.setItem(RECENT_RECIPIENTS_STORAGE_KEY, JSON.stringify(recipients.slice(0, MAX_RECENT_RECIPIENTS)));
    } catch {
        // Ignore storage write errors (private mode / quota / restricted env).
    }
};

const extractPhoneFromUnknownContact = (payload) => {
    const candidates = [];

    const pushCandidate = (value) => {
        if (value == null) return;

        if (Array.isArray(value)) {
            value.forEach((item) => pushCandidate(item));
            return;
        }

        if (typeof value === 'object') {
            pushCandidate(value.number);
            pushCandidate(value.value);
            pushCandidate(value.phoneNumber);
            pushCandidate(value.phone_number);
            pushCandidate(value.tel);
            pushCandidate(value.phone);
            return;
        }

        candidates.push(String(value));
    };

    pushCandidate(payload?.tel);
    pushCandidate(payload?.phone);
    pushCandidate(payload?.phones);
    pushCandidate(payload?.phoneNumbers);
    pushCandidate(payload?.phone_numbers);
    pushCandidate(payload?.contact);
    pushCandidate(payload?.contacts);
    pushCandidate(payload);

    for (const value of candidates) {
        const normalized = normalizeNigeriaPhoneNumber(value);
        if (normalized) return normalized;
    }

    return null;
};

const extractNameFromUnknownContact = (payload) => {
    const primary = payload?.name;
    if (Array.isArray(primary)) {
        const first = String(primary[0] || '').trim();
        if (first) return first;
    }

    if (typeof primary === 'string' && primary.trim()) {
        return primary.trim();
    }

    if (primary && typeof primary === 'object') {
        const display = String(primary.display || primary.displayName || primary.display_name || '').trim();
        if (display) return display;

        const given = String(primary.given || primary.givenName || primary.firstName || primary.first_name || '').trim();
        const family = String(primary.family || primary.familyName || primary.lastName || primary.last_name || '').trim();
        const combined = `${given} ${family}`.trim();
        if (combined) return combined;
    }

    const contactName = String(payload?.displayName || payload?.display_name || payload?.fullName || payload?.full_name || '').trim();
    return contactName;
};

export const useRecipientContactPicker = (options = {}) => {
    const initialRecipients = Array.isArray(options.initialRecipients) ? options.initialRecipients : [];
    const pickerBusy = ref(false);
    const pickerError = ref('');
    const fallbackOpen = ref(false);
    const fallbackMode = ref('recent'); // 'recent' | 'device'
    const fallbackSearch = ref('');
    const recents = ref([]);
    const deviceContacts = ref([]);

    const mergedUniqueRecipients = (entries) => {
        const unique = new Map();
        entries
            .map((entry) => normalizeRecipientEntry(entry))
            .filter((entry) => !!entry)
            .forEach((entry) => {
                const key = entry.phone;
                if (!unique.has(key)) {
                    unique.set(key, entry);
                    return;
                }

                const existing = unique.get(key);
                const currentTs = Date.parse(String(entry.created_at || '')) || 0;
                const existingTs = Date.parse(String(existing.created_at || '')) || 0;
                if (currentTs >= existingTs) {
                    unique.set(key, entry);
                }
            });

        return Array.from(unique.values())
            .sort((a, b) => (Date.parse(String(b.created_at || '')) || 0) - (Date.parse(String(a.created_at || '')) || 0))
            .slice(0, MAX_RECENT_RECIPIENTS);
    };

    const hydrateRecipients = () => {
        const fromStorage = loadLocalRecentRecipients();
        recents.value = mergedUniqueRecipients([...initialRecipients, ...fromStorage]);
        saveLocalRecentRecipients(recents.value);
    };

    hydrateRecipients();

    const activeEntries = computed(() => (fallbackMode.value === 'device' ? deviceContacts.value : recents.value));

    const filteredRecipients = computed(() => {
        const query = String(fallbackSearch.value || '').trim().toLowerCase();
        if (!query) return activeEntries.value;

        return activeEntries.value.filter((entry) =>
            String(entry.phone || '').toLowerCase().includes(query)
            || String(entry.label || '').toLowerCase().includes(query)
        );
    });

    const addRecentRecipient = ({ phone, label = '', source = 'manual' }) => {
        const normalized = normalizeNigeriaPhoneNumber(phone);
        if (!normalized) return;

        recents.value = mergedUniqueRecipients([
            {
                phone: normalized,
                label: String(label || '').trim(),
                source,
                created_at: new Date().toISOString(),
            },
            ...recents.value,
        ]);

        saveLocalRecentRecipients(recents.value);
    };

    const closeFallbackPicker = () => {
        fallbackOpen.value = false;
        fallbackSearch.value = '';
    };

    const openFallbackPicker = () => {
        pickerError.value = '';
        fallbackMode.value = 'recent';
        fallbackOpen.value = true;
    };

    const openDeviceContactsPicker = (contacts) => {
        pickerError.value = '';
        fallbackMode.value = 'device';
        deviceContacts.value = Array.isArray(contacts) ? contacts : [];
        fallbackSearch.value = '';
        fallbackOpen.value = true;
    };

    const fallbackTitle = computed(() => (fallbackMode.value === 'device' ? 'Device Contacts' : 'Recent Recipients'));
    const fallbackHint = computed(() => {
        if (fallbackMode.value === 'device') {
            return 'Select a phone number from your device contacts.';
        }

        return 'Select from your recent recipients. This list also works when device contacts are unavailable.';
    });

    const fallbackSearchPlaceholder = computed(() => (fallbackMode.value === 'device' ? 'Search name or number' : 'Search number or label'));
    const fallbackEmptyMessage = computed(() => {
        if (fallbackMode.value === 'device') {
            return 'No contacts found on this device.';
        }

        return 'No saved recipients found yet. Enter number manually to continue.';
    });

    const pickFromWebContacts = async () => {
        if (typeof navigator === 'undefined' || !navigator.contacts || typeof navigator.contacts.select !== 'function') {
            return null;
        }

        try {
            const selected = await navigator.contacts.select(['name', 'tel'], { multiple: false });
            const first = Array.isArray(selected) ? selected[0] : null;
            const normalizedPhone = extractPhoneFromUnknownContact(first);
            if (!normalizedPhone) return null;

            return {
                phone: normalizedPhone,
                label: extractNameFromUnknownContact(first),
                source: 'web-contacts',
            };
        } catch {
            return null;
        }
    };

    const pickFromCapacitorNative = async () => {
        if (typeof window === 'undefined') return null;
        const capacitor = window.Capacitor || null;
        const plugins = capacitor?.Plugins || null;
        if (!plugins) return null;

        const candidates = [
            plugins.Contacts,
            plugins.ContactPicker,
            plugins.Contact,
        ].filter(Boolean);

        // Try common native plugin APIs; return null silently if unavailable.
        try {
            for (const candidate of candidates) {
                if (!candidate) continue;

                if (typeof candidate.pickContact === 'function') {
                    const result = await candidate.pickContact();
                    const normalizedPhone = extractPhoneFromUnknownContact(result);
                    if (!normalizedPhone) continue;

                    return {
                        kind: 'picked',
                        phone: normalizedPhone,
                        label: extractNameFromUnknownContact(result),
                        source: 'native-contacts',
                    };
                }

                if (typeof candidate.pickContacts === 'function') {
                    const result = await candidate.pickContacts();
                    const first = Array.isArray(result) ? result[0] : result?.contacts?.[0] || result?.contact || result;
                    const normalizedPhone = extractPhoneFromUnknownContact(first);
                    if (!normalizedPhone) continue;

                    return {
                        kind: 'picked',
                        phone: normalizedPhone,
                        label: extractNameFromUnknownContact(first),
                        source: 'native-contacts',
                    };
                }

                if (typeof candidate.getContacts === 'function') {
                    const result = await candidate.getContacts({
                        projection: { name: true, phones: true },
                        limit: 1000,
                    });

                    const contacts = Array.isArray(result?.contacts) ? result.contacts : [];
                    const mapped = contacts
                        .map((contact) => {
                            const normalizedPhone = extractPhoneFromUnknownContact(contact);
                            if (!normalizedPhone) return null;

                            return {
                                phone: normalizedPhone,
                                label: extractNameFromUnknownContact(contact),
                                source: 'native-contacts',
                                created_at: new Date().toISOString(),
                            };
                        })
                        .filter((entry) => !!entry);

                    if (mapped.length) {
                        // Show device contacts inside the in-app picker.
                        return { kind: 'list', contacts: mapped };
                    }
                }
            }
        } catch {
            // Fall through to any alternative plugin method.
        }

        return null;
    };

    const pickPhone = async () => {
        pickerError.value = '';
        pickerBusy.value = true;

        try {
            const nativePicked = await pickFromCapacitorNative();
            if (nativePicked?.kind === 'picked' && nativePicked?.phone) {
                addRecentRecipient(nativePicked);
                return nativePicked;
            }

            if (nativePicked?.kind === 'list') {
                openDeviceContactsPicker(nativePicked.contacts || []);
                return null;
            }

            const webPicked = await pickFromWebContacts();
            if (webPicked?.phone) {
                addRecentRecipient(webPicked);
                return webPicked;
            }

            openFallbackPicker();
            return null;
        } catch {
            pickerError.value = 'Unable to open contact picker on this device right now.';
            openFallbackPicker();
            return null;
        } finally {
            pickerBusy.value = false;
        }
    };

    const pickFromFallback = (entry) => {
        const normalized = normalizeRecipientEntry(entry);
        if (!normalized) return null;
        addRecentRecipient(normalized);
        closeFallbackPicker();
        return normalized;
    };

    return {
        pickerBusy,
        pickerError,
        fallbackOpen,
        fallbackMode,
        fallbackTitle,
        fallbackHint,
        fallbackSearchPlaceholder,
        fallbackEmptyMessage,
        fallbackSearch,
        filteredRecipients,
        pickPhone,
        pickFromFallback,
        openFallbackPicker,
        closeFallbackPicker,
        addRecentRecipient,
    };
};
