package com.lemenzo.messenger.data;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.telephony.PhoneNumberUtils;
import android.util.Log;
import java.util.concurrent.ConcurrentHashMap;

public final class ContactResolver {
    private static final String TAG = "LemenzoContacts";
    private final Context context;
    private final ConcurrentHashMap<String, String> nameCache = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, String> photoCache = new ConcurrentHashMap<>();

    public ContactResolver(Context context) {
        this.context = context.getApplicationContext();
    }

    public void clearCache() {
        nameCache.clear();
        photoCache.clear();
    }

    /**
     * Resolve a batch of conversation participants with one ContactsProvider scan instead
     * of one provider query per conversation. This keeps inbox startup predictable even
     * with hundreds or thousands of threads. Results are stored in the existing caches.
     */
    public void prefetchPresentations(Iterable<String> numbers) {
        java.util.HashMap<String, java.util.ArrayList<String>> wanted = new java.util.HashMap<>();
        if (numbers == null) return;
        for (String number : numbers) {
            if (number == null || number.trim().isEmpty() || number.contains(",")) continue;
            String key = normalizeKey(number);
            if (key.isEmpty()) continue;
            // Already-resolved contacts (including cached misses) must not trigger another
            // full ContactsProvider scan on every inbox refresh.
            if (nameCache.containsKey(number) && photoCache.containsKey(number)) continue;
            wanted.computeIfAbsent(key, k -> new java.util.ArrayList<>()).add(number);
        }
        if (wanted.isEmpty()) return;

        try (Cursor c = context.getContentResolver().query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                new String[]{
                        ContactsContract.CommonDataKinds.Phone.NUMBER,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                        ContactsContract.CommonDataKinds.Phone.PHOTO_URI
                }, null, null, null)) {
            if (c != null) {
                while (c.moveToNext() && !wanted.isEmpty()) {
                    String stored = c.getString(0);
                    String key = normalizeKey(stored);
                    java.util.ArrayList<String> originals = wanted.remove(key);
                    if (originals == null) continue;
                    String name = c.getString(1);
                    String photo = c.getString(2);
                    for (String original : originals) {
                        nameCache.put(original, name == null || name.isEmpty() ? original : name);
                        photoCache.put(original, photo == null ? "" : photo);
                    }
                }
            }
        } catch (SecurityException e) {
            Log.w(TAG, "Contacts permission unavailable");
        } catch (RuntimeException e) {
            Log.w(TAG, "Batch contact lookup failed", e);
        }

        // Resolve any formatting/country-code mismatches through PhoneLookup and,
        // if needed, PhoneNumberUtils.compare before caching a miss as the raw number.
        for (java.util.ArrayList<String> originals : wanted.values()) {
            for (String original : originals) {
                ContactRecord record = lookup(original);
                String name = record.name;
                String photo = record.photoUri;
                if (record.contactId < 0) {
                    ContactRecord comparable = lookupComparable(original);
                    if (comparable.contactId >= 0) {
                        name = comparable.name;
                        photo = comparable.photoUri;
                    }
                }
                nameCache.put(original, name == null || name.isEmpty() ? original : name);
                photoCache.put(original, photo == null ? "" : photo);
            }
        }
    }

    private static String normalizeKey(String number) {
        if (number == null) return "";
        String trimmed = number.trim();
        String normalized = PhoneNumberUtils.normalizeNumber(trimmed);
        if (trimmed.startsWith("+") && !normalized.startsWith("+")) normalized = "+" + normalized;
        return normalized;
    }

    public String displayName(String number) {
        if (number == null || number.isEmpty()) return "";
        String cached = nameCache.get(number);
        if (cached != null) return cached;
        ContactRecord record = lookup(number);
        String result = record.name == null || record.name.isEmpty() ? number : record.name;
        nameCache.put(number, result);
        photoCache.put(number, record.photoUri == null ? "" : record.photoUri);
        return result;
    }

    public String resolveAddress(String input) {
        if (input == null) return null;
        String value = input.trim();
        if (value.isEmpty()) return null;

        String normalized = PhoneNumberUtils.normalizeNumber(value);
        if (value.startsWith("+") && !normalized.startsWith("+")) normalized = "+" + normalized;
        if (!normalized.isEmpty() && PhoneNumberUtils.isGlobalPhoneNumber(normalized)) return normalized;

        String found = null;
        try (Cursor c = context.getContentResolver().query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                new String[]{
                        ContactsContract.CommonDataKinds.Phone.NUMBER,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
                },
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " LIKE ?",
                new String[]{value},
                ContactsContract.CommonDataKinds.Phone.IS_PRIMARY + " DESC")) {
            if (c != null) {
                while (c.moveToNext()) {
                    String name = c.getString(1);
                    if (name == null || !name.equalsIgnoreCase(value)) continue;
                    String number = c.getString(0);
                    if (number == null || number.trim().isEmpty()) continue;
                    String candidate = PhoneNumberUtils.normalizeNumber(number);
                    if (number.trim().startsWith("+") && !candidate.startsWith("+")) candidate = "+" + candidate;
                    if (candidate.isEmpty()) continue;
                    if (found == null) found = candidate;
                    else if (!PhoneNumberUtils.compare(found, candidate)) return null;
                }
            }
        } catch (SecurityException e) {
            Log.w(TAG, "Contacts permission unavailable");
        } catch (RuntimeException e) {
            Log.w(TAG, "Contact name resolution failed", e);
        }
        return found;
    }

    public Uri photoUri(String number) {
        if (number == null || number.isEmpty()) return null;
        String cached = photoCache.get(number);
        if (cached != null) return cached.isEmpty() ? null : Uri.parse(cached);
        ContactRecord record = lookup(number);
        if (record.name != null && !record.name.isEmpty()) nameCache.put(number, record.name);
        photoCache.put(number, record.photoUri == null ? "" : record.photoUri);
        return record.photoUri == null ? null : Uri.parse(record.photoUri);
    }


    public boolean isSavedContact(String number) {
        if (number == null || number.trim().isEmpty()) return false;
        ContactRecord record = lookup(number);
        return record.contactId >= 0;
    }

    public Uri contactUri(String number) {
        if (number == null || number.trim().isEmpty()) return null;
        ContactRecord record = lookup(number);
        if (record.contactId < 0 || record.lookupKey == null || record.lookupKey.isEmpty()) return null;
        return ContactsContract.Contacts.getLookupUri(record.contactId, record.lookupKey);
    }

    private ContactRecord lookup(String number) {
        Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
        try (Cursor c = context.getContentResolver().query(
                uri,
                new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup.PHOTO_URI,
                        ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.LOOKUP_KEY},
                null,
                null,
                null)) {
            if (c != null && c.moveToFirst()) {
                return new ContactRecord(c.getString(0), c.getString(1), c.getLong(2), c.getString(3));
            }
        } catch (SecurityException e) {
            Log.w(TAG, "Contacts permission unavailable");
        } catch (RuntimeException e) {
            Log.w(TAG, "Contact lookup failed", e);
        }
        return lookupComparable(number);
    }

    private ContactRecord lookupComparable(String number) {
        if (number == null || number.trim().isEmpty()) {
            return new ContactRecord(number, null, -1L, null);
        }
        try (Cursor c = context.getContentResolver().query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                new String[]{
                        ContactsContract.CommonDataKinds.Phone.NUMBER,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                        ContactsContract.CommonDataKinds.Phone.PHOTO_URI,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                        ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY
                }, null, null, null)) {
            if (c != null) {
                while (c.moveToNext()) {
                    String stored = c.getString(0);
                    if (stored == null || !PhoneNumberUtils.compare(stored, number)) continue;
                    return new ContactRecord(c.getString(1), c.getString(2), c.getLong(3), c.getString(4));
                }
            }
        } catch (SecurityException e) {
            Log.w(TAG, "Contacts permission unavailable");
        } catch (RuntimeException e) {
            Log.w(TAG, "Comparable contact lookup failed", e);
        }
        return new ContactRecord(number, null, -1L, null);
    }

    private static final class ContactRecord {
        final String name;
        final String photoUri;
        final long contactId;
        final String lookupKey;
        ContactRecord(String name, String photoUri, long contactId, String lookupKey) {
            this.name = name;
            this.photoUri = photoUri;
            this.contactId = contactId;
            this.lookupKey = lookupKey;
        }
    }
}
