package chat.vojo.app;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;

import androidx.core.app.NotificationCompat;

/**
 * Foreground service kept alive for the duration of an active DM call. Its
 * sole job is to promote the process to PROCESS_STATE_FOREGROUND_SERVICE so
 * Android doesn't:
 *   - revoke RECORD_AUDIO via AppOps (API 31+ while-in-use gating);
 *   - apply background network firewall via netd.
 *
 * Both revocations were observed in Phase 0 capture on Samsung OneUI API 36:
 * mic went Active=false ~5s after screen-off, netd isBlocked=true ~13s after,
 * causing Element Call inside the hidden WebView to tear down the LiveKit
 * session and the call to drop.
 *
 * Preconditions enforced by callers:
 *   - RECORD_AUDIO runtime permission granted (plugin-side check in
 *     CallForegroundPlugin.start). The manifest declares
 *     foregroundServiceType="microphone" only, so TYPE_NONE is not a valid
 *     fallback on API 34+ — we never attempt one.
 *   - JS side gates on useCallJoined so the widget's getUserMedia has already
 *     prompted for and received the grant by the time we start.
 */
public class CallForegroundService extends Service {

    public static final String EXTRA_TITLE = "title";
    public static final String EXTRA_BODY = "body";

    private static final String CHANNEL_ID = "vojo_calls_ongoing";
    // Stable id, distinct from VojoFirebaseMessagingService.SUMMARY_NOTIFICATION_ID
    // (Integer.MIN_VALUE) and from per-room call ids (String.hashCode of "call_<roomId>").
    private static final int NOTIFICATION_ID = 0x766F6A6F; // "vojo" as ASCII bytes

    private static final String TAG = "CallFgs";

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String title = intent != null ? intent.getStringExtra(EXTRA_TITLE) : null;
        String body = intent != null ? intent.getStringExtra(EXTRA_BODY) : null;
        if (title == null || title.isEmpty()) title = "Активный звонок";
        if (body == null) body = "";

        NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (nm == null) {
            Log.w(TAG, "onStartCommand: NotificationManager null, cannot start FGS");
            stopSelf(startId);
            return START_NOT_STICKY;
        }

        ensureOngoingChannel(nm);

        Intent launchIntent = new Intent(this, MainActivity.class)
            .setAction(Intent.ACTION_MAIN)
            .addCategory(Intent.CATEGORY_LAUNCHER)
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        int piFlags = PendingIntent.FLAG_UPDATE_CURRENT
            | (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0);
        PendingIntent launchPI = PendingIntent.getActivity(this, 0, launchIntent, piFlags);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setContentText(body)
            .setCategory(NotificationCompat.CATEGORY_CALL)
            .setOngoing(true)
            .setAutoCancel(false)
            .setOnlyAlertOnce(true)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setContentIntent(launchPI);

        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                // API 30+: FOREGROUND_SERVICE_TYPE_MICROPHONE constant exists
                // and 3-arg startForeground is available. API 34+ REQUIRES
                // the type to match the manifest — we declared `microphone`
                // and always pass it. RECORD_AUDIO grant is ensured by
                // CallForegroundPlugin before this code runs.
                startForeground(NOTIFICATION_ID, builder.build(),
                    ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
                Log.d(TAG, "startForeground ok type=microphone");
            } else {
                // API 24-29: 2-arg form; manifest foregroundServiceType attribute
                // is enough for the OS to classify the service correctly.
                startForeground(NOTIFICATION_ID, builder.build());
                Log.d(TAG, "startForeground ok (pre-R, manifest-driven type)");
            }
        } catch (Throwable t) {
            // If startForeground with TYPE_MICROPHONE throws despite our
            // precondition checks (unexpected OEM behavior, race, manifest
            // drift), we intentionally do NOT retry with TYPE_NONE — that is
            // invalid on API 34+ when the manifest declares `microphone`.
            // Better to surface the failure and let the call proceed without
            // retention than to silently crash with ForegroundServiceTypeException.
            Log.e(TAG, "startForeground threw, stopping service without retry", t);
            stopSelf(startId);
        }

        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        // Belt-and-suspenders: if the service is being stopped via stopService
        // and the FGS flag is still up, make sure the notification goes away.
        // Idempotent if stopForeground was already called elsewhere.
        stopForeground(STOP_FOREGROUND_REMOVE);
        super.onDestroy();
    }

    private void ensureOngoingChannel(NotificationManager nm) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
        if (nm.getNotificationChannel(CHANNEL_ID) != null) return;
        NotificationChannel channel = new NotificationChannel(
            CHANNEL_ID,
            "Активные звонки",
            NotificationManager.IMPORTANCE_LOW
        );
        channel.setDescription("Уведомление во время активного звонка Vojo");
        channel.setShowBadge(false);
        channel.enableLights(false);
        channel.enableVibration(false);
        channel.setSound(null, null);
        nm.createNotificationChannel(channel);
    }
}
