package com.lemenzo.messenger.data;

import android.content.Context;
import android.content.SharedPreferences;
import com.lemenzo.messenger.model.PendingMessage;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public final class PendingMessageStore {
    private static final String PREFS = "lemenzo_pending_messages";
    private static final String TOKENS = "tokens";
    private static final Object LOCK = new Object();
    private final SharedPreferences prefs;

    public PendingMessageStore(Context context) {
        prefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
    }

    public SharedPreferences preferences() { return prefs; }

    public void add(String token, String address, String body, long date, int subscriptionId) {
        addInternal(token, address, body, date, subscriptionId, PendingMessage.PROTOCOL_SMS, null);
    }

    public void addMms(String token, String address, String body, long date, int subscriptionId,
            String attachmentUri) {
        addInternal(token, address, body, date, subscriptionId, PendingMessage.PROTOCOL_MMS,
                attachmentUri);
    }

    private void addInternal(String token, String address, String body, long date, int subscriptionId,
            int protocol, String attachmentUri) {
        synchronized (LOCK) {
            Set<String> tokens = new HashSet<>(prefs.getStringSet(TOKENS, new HashSet<>()));
            tokens.add(token);
            SharedPreferences.Editor edit = prefs.edit().putStringSet(TOKENS, tokens)
                    .putString(token + ".address", address)
                    .putString(token + ".body", body)
                    .putLong(token + ".date", date)
                    .putInt(token + ".subscription", subscriptionId)
                    .putInt(token + ".state", PendingMessage.STATE_SENDING)
                    .putInt(token + ".protocol", protocol);
            if (attachmentUri != null) edit.putString(token + ".attachment", attachmentUri);
            edit.commit();
        }
    }

    public void markSending(String token) {
        synchronized (LOCK) {
            if (!contains(token)) return;
            prefs.edit().putInt(token + ".state", PendingMessage.STATE_SENDING).commit();
        }
    }

    public void markFailed(String token) {
        synchronized (LOCK) {
            if (!contains(token)) return;
            prefs.edit().putInt(token + ".state", PendingMessage.STATE_FAILED).commit();
        }
    }

    public void markSent(String token) {
        synchronized (LOCK) {
            if (!contains(token)) return;
            prefs.edit().putInt(token + ".state", PendingMessage.STATE_SENT).commit();
        }
    }

    public void remove(String token) {
        synchronized (LOCK) {
            Set<String> tokens = new HashSet<>(prefs.getStringSet(TOKENS, new HashSet<>()));
            tokens.remove(token);
            prefs.edit().putStringSet(TOKENS, tokens)
                    .remove(token + ".address").remove(token + ".body")
                    .remove(token + ".date").remove(token + ".subscription")
                    .remove(token + ".state").remove(token + ".protocol")
                    .remove(token + ".attachment").commit();
        }
    }

    public void removeOlderThan(long cutoff) {
        List<String> remove = new ArrayList<>();
        synchronized (LOCK) {
            for (String token : new HashSet<>(prefs.getStringSet(TOKENS, new HashSet<>()))) {
                if (prefs.getLong(token + ".date", Long.MAX_VALUE) < cutoff) remove.add(token);
            }
        }
        for (String token : remove) remove(token);
    }

    public void removeForAddress(String address) {
        if (address == null) return;
        List<String> remove = new ArrayList<>();
        synchronized (LOCK) {
            for (String token : new HashSet<>(prefs.getStringSet(TOKENS, new HashSet<>()))) {
                String storedAddress = prefs.getString(token + ".address", null);
                if (storedAddress != null && sameRecipients(storedAddress, address)) remove.add(token);
            }
        }
        for (String token : remove) remove(token);
    }

    public boolean hasForAddress(String address) {
        return !forAddress(address).isEmpty();
    }

    public List<PendingMessage> all() {
        List<PendingMessage> out = new ArrayList<>();
        synchronized (LOCK) {
            for (String token : new HashSet<>(prefs.getStringSet(TOKENS, new HashSet<>()))) {
                PendingMessage m = read(token);
                if (m != null) out.add(m);
            }
        }
        out.sort((a, b) -> Long.compare(b.date, a.date));
        return out;
    }

    public List<PendingMessage> forAddress(String address) {
        List<PendingMessage> out = new ArrayList<>();
        synchronized (LOCK) {
            for (String token : new HashSet<>(prefs.getStringSet(TOKENS, new HashSet<>()))) {
                String storedAddress = prefs.getString(token + ".address", null);
                if (storedAddress == null || !sameRecipients(storedAddress, address)) continue;
                PendingMessage m = read(token);
                if (m != null) out.add(m);
            }
        }
        out.sort((a, b) -> Long.compare(a.date, b.date));
        return out;
    }

    public PendingMessage get(String token) {
        synchronized (LOCK) { return contains(token) ? read(token) : null; }
    }

    private PendingMessage read(String token) {
        PendingMessage m = new PendingMessage();
        m.token = token;
        m.address = prefs.getString(token + ".address", null);
        m.body = prefs.getString(token + ".body", "");
        m.date = prefs.getLong(token + ".date", 0L);
        m.subscriptionId = prefs.getInt(token + ".subscription",
                android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        m.state = prefs.getInt(token + ".state", PendingMessage.STATE_SENDING);
        m.protocol = prefs.getInt(token + ".protocol", PendingMessage.PROTOCOL_SMS);
        m.attachmentUri = prefs.getString(token + ".attachment", null);
        return m;
    }

    private boolean contains(String token) {
        return new HashSet<>(prefs.getStringSet(TOKENS, new HashSet<>())).contains(token);
    }

    private static boolean sameRecipients(String a, String b) {
        if (a == null || b == null) return false;
        if (a.equals(b)) return true;
        return normalize(a).equals(normalize(b));
    }

    private static String normalize(String value) {
        String[] parts = value.split("[,;]");
        java.util.Arrays.sort(parts, String.CASE_INSENSITIVE_ORDER);
        StringBuilder out = new StringBuilder();
        for (String part : parts) {
            String s = part.trim();
            if (!s.isEmpty()) out.append(s).append('|');
        }
        return out.toString();
    }
}
