package com.lemenzo.messenger.mms;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.telephony.SmsManager;
import android.util.Log;
import com.google.android.mms.MmsException;
import com.google.android.mms.pdu.GenericPdu;
import com.google.android.mms.pdu.PduHeaders;
import com.google.android.mms.pdu.SendConf;
import com.lemenzo.messenger.data.PendingMessageStore;
import com.lemenzo.messenger.util.ReceiverAsync;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public final class MmsSendResultReceiver extends BroadcastReceiver {
    public static final String ACTION_MMS_SENT = "com.lemenzo.messenger.MMS_SENT";
    private static final String TAG = "LemenzoMessengerMms";

    @Override public void onReceive(Context context, Intent intent) {
        final String raw = intent.getStringExtra("content_uri");
        final String token = intent.getStringExtra("token");
        if (raw == null || token == null) return;
        final int subscriptionId = intent.getIntExtra("subscription_id",
                android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        final int resultCode = getResultCode();
        final byte[] sourceResponse = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA);
        final byte[] response = sourceResponse == null ? null : sourceResponse.clone();
        final Context appContext = context.getApplicationContext();
        ReceiverAsync.run(this, () -> finishSend(
                appContext, raw, token, subscriptionId, resultCode, response));
    }

    private static void finishSend(
            Context context, String raw, String token, int subscriptionId,
            int resultCode, byte[] response) {
        Uri rawUri = Uri.parse(raw);
        PendingMessageStore store = new PendingMessageStore(context);

        try {
            if (resultCode != Activity.RESULT_OK) {
                Log.w(TAG, "MMS send failed: " + resultCode);
                store.markFailed(token);
                return;
            }

            if (response != null && response.length > 0) {
                GenericPdu parsed = MmsPduUtils.parse(response);
                if (parsed instanceof SendConf
                        && ((SendConf) parsed).getResponseStatus() != PduHeaders.RESPONSE_STATUS_OK) {
                    Log.w(TAG, "MMSC rejected send");
                    store.markFailed(token);
                    return;
                }
            }

            if (store.get(token) == null) {
                return;
            }

            File file = MmsFileProvider.fileFor(context, rawUri);
            byte[] outgoing = readFully(file);
            GenericPdu sentPdu = MmsPduUtils.parse(outgoing);
            if (sentPdu == null) {
                store.markFailed(token);
                return;
            }

            try {
                Uri persisted = MmsPduUtils.persistSent(context, sentPdu);
                if (persisted != null) {
                    android.content.ContentValues values = new android.content.ContentValues();
                    values.put(android.provider.Telephony.Mms.SUBSCRIPTION_ID, subscriptionId);
                    values.put(android.provider.Telephony.Mms.READ, 1);
                    values.put(android.provider.Telephony.Mms.SEEN, 1);
                    try { context.getContentResolver().update(persisted, values, null, null); }
                    catch (RuntimeException ignored) {}
                }
                store.remove(token);
            } catch (MmsException e) {
                store.markSent(token);
                Log.e(TAG, "MMS sent but provider persistence failed", e);
            }
        } catch (IOException | RuntimeException e) {
            store.markFailed(token);
            Log.e(TAG, "Unable to finalize sent MMS", e);
        } finally {
            MmsFileProvider.delete(context, rawUri);
        }
    }

    private static byte[] readFully(File file) throws IOException {
        long length = file.length();
        if (length <= 0 || length > 12L * 1024L * 1024L) throw new IOException("Invalid PDU size");
        byte[] out = new byte[(int) length];
        try (FileInputStream in = new FileInputStream(file)) {
            int offset = 0;
            while (offset < out.length) {
                int n = in.read(out, offset, out.length - offset);
                if (n < 0) break;
                offset += n;
            }
            if (offset != out.length) throw new IOException("Short PDU read");
        }
        return out;
    }
}
