package com.lemenzo.messenger.sms;

import android.content.Context;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
import com.lemenzo.messenger.data.MessageRepository;
import com.lemenzo.messenger.data.BroadcastStore;
import com.lemenzo.messenger.data.PendingMessageStore;

public final class MultipartSendTracker {
    private static final String PREFS = "lemenzo_multipart_send";
    private static final Object LOCK = new Object();

    private MultipartSendTracker() {}

    static void begin(
            Context c,
            String token,
            String address,
            String body,
            int parts,
            int subscriptionId) {
        begin(c, token, address, body, parts, subscriptionId, null, null, null);
    }

    static void begin(
            Context c,
            String token,
            String address,
            String body,
            int parts,
            int subscriptionId,
            String externalRequestId) {
        begin(c, token, address, body, parts, subscriptionId, externalRequestId, null, null);
    }

    static void begin(
            Context c,
            String token,
            String address,
            String body,
            int parts,
            int subscriptionId,
            String externalRequestId,
            String broadcastId) {
        begin(c, token, address, body, parts, subscriptionId,
                externalRequestId, broadcastId, null);
    }

    static void begin(
            Context c,
            String token,
            String address,
            String body,
            int parts,
            int subscriptionId,
            String externalRequestId,
            String broadcastId,
            String broadcastMessageId) {
        synchronized (LOCK) {
            c.getSharedPreferences(PREFS, Context.MODE_PRIVATE).edit()
                    .putString(token + ".address", address)
                    .putString(token + ".body", body)
                    .putInt(token + ".parts", parts)
                    .putInt(token + ".subscription_id", subscriptionId)
                    .putInt(token + ".completed", 0)
                    .putBoolean(token + ".failed", false)
                    .putString(token + ".external_request_id", externalRequestId)
                    .putString(token + ".broadcast_id", broadcastId)
                    .putString(token + ".broadcast_message_id", broadcastMessageId)
                    .commit();
        }
    }

    public static boolean isBroadcastToken(Context c, String token) {
        if (token == null || token.isEmpty()) return false;
        String id = c.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
                .getString(token + ".broadcast_id", null);
        return id != null && !id.isEmpty();
    }

    static void recordSentPart(Context c, String token, boolean success) {
        synchronized (LOCK) {
            SharedPreferences p = c.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
            int total = p.getInt(token + ".parts", 0);
            if (total <= 0) return;

            int completed = p.getInt(token + ".completed", 0) + 1;
            boolean failed = p.getBoolean(token + ".failed", false) || !success;

            p.edit()
                    .putInt(token + ".completed", completed)
                    .putBoolean(token + ".failed", failed)
                    .commit();

            if (completed < total) return;

            PendingMessageStore pending = new PendingMessageStore(c);
            if (failed) {
                pending.markFailed(token);
                String failedBroadcastId = p.getString(token + ".broadcast_id", null);
                if (failedBroadcastId != null && addressFor(p, token) != null) {
                    new BroadcastStore(c).updateRecipient(
                            failedBroadcastId,
                            p.getString(token + ".broadcast_message_id", null),
                            addressFor(p, token),
                            "failed");
                    pending.remove(token);
                }
                sendExternalStatus(
                        c,
                        p.getString(token + ".external_request_id", null),
                        "failed");
                clear(p, token);
                return;
            }

            if (pending.get(token) == null) {
                clear(p, token);
                return;
            }

            String address = p.getString(token + ".address", null);
            String body = p.getString(token + ".body", null);
            int subscriptionId = p.getInt(token + ".subscription_id",
                    android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID);

            String broadcastId = p.getString(token + ".broadcast_id", null);
            if (broadcastId != null && !broadcastId.isEmpty()) {
                // A private broadcast is represented locally as one broadcast record.
                // Do not insert ten separate sent rows into Telephony.Sms, because that
                // would make the sender inbox show ten individual conversations.
                new BroadcastStore(c).updateRecipient(
                        broadcastId,
                        p.getString(token + ".broadcast_message_id", null),
                        address,
                        "sent");
                pending.remove(token);
            } else {
                boolean persisted = false;
                if (address != null && body != null) {
                    try {
                        persisted = new MessageRepository(c)
                                .insertSent(address, body, System.currentTimeMillis(), subscriptionId) != null;
                    } catch (SecurityException ignored) {
                    }
                }
                if (persisted) pending.remove(token);
                else pending.markSent(token);
            }

            sendExternalStatus(
                    c,
                    p.getString(token + ".external_request_id", null),
                    "sent");
            clear(p, token);
        }
    }

    static void cancel(Context c, String token) {
        synchronized (LOCK) {
            clear(c.getSharedPreferences(PREFS, Context.MODE_PRIVATE), token);
        }
    }

    private static void sendExternalStatus(
            Context c,
            String requestId,
            String status) {
        if (requestId == null || requestId.isEmpty()) {
            return;
        }
        Intent result = new Intent("com.lemenzo.multisms.BULK_STATUS")
                .setComponent(new ComponentName(
                        "com.lemenzo.multisms",
                        "com.lemenzo.multisms.BulkStatusReceiver"))
                .putExtra("request_id", requestId)
                .putExtra("status", status);
        c.sendBroadcast(
                result,
                "com.lemenzo.permission.MULTI_SMS");
    }

    private static String addressFor(SharedPreferences p, String token) {
        return p.getString(token + ".address", null);
    }

    private static void clear(SharedPreferences p, String token) {
        p.edit()
                .remove(token + ".address")
                .remove(token + ".body")
                .remove(token + ".parts")
                .remove(token + ".subscription_id")
                .remove(token + ".completed")
                .remove(token + ".failed")
                .remove(token + ".external_request_id")
                .remove(token + ".broadcast_id")
                .remove(token + ".broadcast_message_id")
                .commit();
    }
}
