package com.foxx.androidcast;

import android.app.ForegroundServiceStartNotAllowedException;
import android.app.Notification;
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.os.Build;
import android.util.Log;

import androidx.core.app.NotificationCompat;

import com.foxx.androidcast.dev.DevAdbConnectInfo;
import com.foxx.androidcast.dev.DevAdbWifiKeeper;
import com.foxx.androidcast.remoteaccess.RemoteAccessMode;
import com.foxx.androidcast.remoteaccess.RemoteAccessStatusStore;

/**
 * Single persistent status-bar notification for Android Cast (prod + dev modes).
 */
public final class CastTrayNotifier {
    private static final String TAG = "CastTrayNotifier";
    public static final String CHANNEL_TRAY = "cast_tray";
    public static final int ID_TRAY = 3;

    /** Legacy per-feature notification ids — cancelled on every refresh. */
    public static final int LEGACY_DEV_ADB_ID = 50391;
    public static final int LEGACY_RA_ID = 0x7a00;
    public static final int LEGACY_RA_VPN_ID = 0x7a01;

    private CastTrayNotifier() {}

    /** Sync tray content with app / dev service state. */
    public static void refresh(Context context) {
        Context app = context.getApplicationContext();
        cancelLegacyNotifications(app);
        if (!shouldMaintainTray(app)) {
            stopTrayService(app);
            hide(app);
            return;
        }
        ensureTrayService(app);
        publish(app);
    }

    public static void syncWhenForeground(Context context) {
        if (shouldMaintainTray(context)) {
            ensureTrayService(context);
        }
    }

    public static void onPreferenceChanged(Context context) {
        refresh(context);
    }

    public static boolean shouldMaintainTray(Context context) {
        if (AppPreferences.isShowTrayIcon(context)) {
            return true;
        }
        return hasDevTrayContent(context);
    }

    static boolean hasDevTrayContent(Context context) {
        if (!BuildConfig.DEBUG) {
            return false;
        }
        if (AppPreferences.isDevAdbWifiKeeperEnabled(context)) {
            return true;
        }
        return AppPreferences.getDevRemoteAccessMode(context).isActive();
    }

    public static void ensureTrayService(Context context) {
        Context app = context.getApplicationContext();
        if (!shouldMaintainTray(app)) {
            return;
        }
        Intent intent = new Intent(app, TrayForegroundService.class);
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                app.startForegroundService(intent);
            } else {
                app.startService(intent);
            }
        } catch (ForegroundServiceStartNotAllowedException e) {
            Log.w(TAG, "tray FGS deferred (not foreground): " + e.getMessage());
        } catch (IllegalStateException e) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                Log.w(TAG, "tray FGS deferred: " + e.getMessage());
            } else {
                throw e;
            }
        }
    }

    public static void stopTrayService(Context context) {
        context.getApplicationContext().stopService(new Intent(context, TrayForegroundService.class));
    }

    /** Foreground tray owned by {@link TrayForegroundService}. */
    public static void startForegroundTray(Service service) {
        if (!shouldMaintainTray(service)) {
            service.stopSelf();
            return;
        }
        createChannel(service);
        Notification n = buildNotification(service);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            service.startForeground(
                    ID_TRAY,
                    n,
                    android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
        } else {
            service.startForeground(ID_TRAY, n);
        }
    }

    /** Other foreground services reuse the same tray notification id. */
    public static void startForeground(Service service, int fgsType) {
        createChannel(service);
        Notification n = buildNotification(service);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && fgsType != 0) {
            service.startForeground(ID_TRAY, n, fgsType);
        } else {
            service.startForeground(ID_TRAY, n);
        }
    }

    public static Notification buildNotification(Context context) {
        createChannel(context);
        boolean casting = CastActiveState.isSenderCasting() || CastActiveState.isReceiverListening();
        boolean adbEnabled = BuildConfig.DEBUG && AppPreferences.isDevAdbWifiKeeperEnabled(context);
        RemoteAccessMode raMode = BuildConfig.DEBUG
                ? AppPreferences.getDevRemoteAccessMode(context)
                : RemoteAccessMode.DISABLED;
        RemoteAccessStatusStore.Snapshot raSnap = RemoteAccessStatusStore.load(context);
        DevAdbConnectInfo adbInfo = adbEnabled ? DevAdbWifiKeeper.getLastInfo(context) : null;
        String adbLine = adbInfo != null ? adbInfo.primaryConnectLine() : "";

        CastTrayContent.Body body = CastTrayContent.build(
                context.getString(R.string.tray_cast_idle),
                context.getString(R.string.tray_cast_active),
                context.getString(R.string.dev_adb_wifi_notification_waiting),
                context.getString(R.string.dev_adb_wifi_notification_line),
                context.getString(R.string.dev_remote_access_notification_poll),
                context.getString(R.string.dev_remote_access_notification_connected),
                context.getString(R.string.dev_remote_access_notification_session),
                casting,
                adbEnabled,
                adbLine,
                raMode,
                raSnap);

        PendingIntent pi = PendingIntent.getActivity(
                context, 0, CastActivityTracker.resumeIntent(context),
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        Intent deleted = new Intent(context, TrayNotificationReceiver.class);
        deleted.setAction("com.foxx.androidcast.TRAY_DISMISSED");
        PendingIntent deletePi = PendingIntent.getBroadcast(
                context, 1, deleted,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_TRAY)
                .setContentTitle(context.getString(R.string.app_name))
                .setContentText(body.summary)
                .setSmallIcon(R.drawable.ic_notification)
                .setContentIntent(pi)
                .setDeleteIntent(deletePi)
                .setOngoing(true)
                .setAutoCancel(false)
                .setOnlyAlertOnce(true)
                .setShowWhen(false)
                .setLocalOnly(true)
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setCategory(NotificationCompat.CATEGORY_SERVICE)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE);
        if (!body.bigText.equals(body.summary)) {
            builder.setStyle(new NotificationCompat.BigTextStyle().bigText(body.bigText));
        }
        return builder.build();
    }

    static void publish(Context context) {
        if (!shouldMaintainTray(context)) {
            return;
        }
        NotificationManager nm = context.getSystemService(NotificationManager.class);
        if (nm != null) {
            nm.notify(ID_TRAY, buildNotification(context));
        }
    }

    static void cancelLegacyNotifications(Context context) {
        NotificationManager nm = context.getSystemService(NotificationManager.class);
        if (nm == null) {
            return;
        }
        nm.cancel(LEGACY_DEV_ADB_ID);
        nm.cancel(LEGACY_RA_ID);
        nm.cancel(LEGACY_RA_VPN_ID);
    }

    private static void hide(Context context) {
        NotificationManager nm = context.getSystemService(NotificationManager.class);
        if (nm != null) {
            nm.cancel(ID_TRAY);
        }
    }

    private static void createChannel(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            return;
        }
        NotificationManager nm = context.getSystemService(NotificationManager.class);
        if (nm == null) {
            return;
        }
        NotificationChannel existing = nm.getNotificationChannel(CHANNEL_TRAY);
        if (existing != null && existing.getImportance() < NotificationManager.IMPORTANCE_DEFAULT) {
            nm.deleteNotificationChannel(CHANNEL_TRAY);
        }
        if (nm.getNotificationChannel(CHANNEL_TRAY) == null) {
            NotificationChannel ch = new NotificationChannel(
                    CHANNEL_TRAY,
                    context.getString(R.string.tray_channel_name),
                    NotificationManager.IMPORTANCE_DEFAULT);
            ch.setDescription(context.getString(R.string.tray_channel_description));
            ch.setShowBadge(true);
            nm.createNotificationChannel(ch);
        }
    }
}
