package com.lemenzo.clock.alarm;
import android.app.*;import android.content.*;import android.media.*;import android.net.Uri;import android.os.*;import android.provider.Settings;import com.lemenzo.clock.R;import com.lemenzo.clock.settings.ClockSettings;import com.lemenzo.clock.model.Alarm;import com.lemenzo.clock.notifications.NotificationChannels;import java.util.*;
public final class AlarmService extends android.app.Service{
 public static final String ACTION_REMOVE="com.lemenzo.clock.alarm.REMOVE_RINGING";private static final LinkedHashSet<Long> ringing=new LinkedHashSet<>();private MediaPlayer player;private Vibrator vib;private Handler volumeHandler;private NotificationManager nm;private long playingId=-1;
 public static synchronized long currentAlarmId(){return ringing.isEmpty()?-1:ringing.iterator().next();}
 @Override public int onStartCommand(Intent i,int flags,int startId){if(i==null)return START_NOT_STICKY;long id=i.getLongExtra(AlarmIntentActions.EXTRA_ID,-1);if(ACTION_REMOVE.equals(i.getAction())){remove(id);return START_NOT_STICKY;}Alarm a=new AlarmRepository(this).get(id);if(a==null){remove(id);return START_NOT_STICKY;}synchronized(AlarmService.class){ringing.add(id);}nm=getSystemService(NotificationManager.class);Notification n=notification(a);if(currentAlarmId()==id&&playingId<0){startForeground(notificationId(id),n);startPrimary(a);}else if(nm!=null)nm.notify(notificationId(id),n);int timeout=new ClockSettings(this).silenceAfterMinutes();if(timeout>0)new Handler(Looper.getMainLooper()).postDelayed(()->remove(id),timeout*60000L);return START_NOT_STICKY;}
 private void remove(long id){boolean wasPrimary=id==currentAlarmId();synchronized(AlarmService.class){ringing.remove(id);}if(nm==null)nm=getSystemService(NotificationManager.class);if(nm!=null)nm.cancel(notificationId(id));if(wasPrimary){stopPlayback();Long next=null;synchronized(AlarmService.class){if(!ringing.isEmpty())next=ringing.iterator().next();}if(next!=null){Alarm a=new AlarmRepository(this).get(next);if(a!=null){startForeground(notificationId(next),notification(a));startPrimary(a);return;}}}synchronized(AlarmService.class){if(ringing.isEmpty())stopSelf();}}
 private void startPrimary(Alarm a){playingId=a.id;play(a);}
 private Notification notification(Alarm a){Intent full=new Intent(this,AlarmRingingActivity.class).putExtra(AlarmIntentActions.EXTRA_ID,a.id).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);PendingIntent fs=PendingIntent.getActivity(this,code(a.id)^7,full,PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE);PendingIntent sn=action(a.id,AlarmIntentActions.SNOOZE,8),di=action(a.id,AlarmIntentActions.DISMISS,9);String title=a.label.isEmpty()?getString(R.string.alarm):a.label;return new Notification.Builder(this,NotificationChannels.ALARMS).setSmallIcon(R.drawable.ic_notification_clock).setContentTitle(title).setContentText(String.format(java.util.Locale.getDefault(),"%02d:%02d",a.hour,a.minute)).setCategory(Notification.CATEGORY_ALARM).setVisibility(Notification.VISIBILITY_PUBLIC).setOngoing(true).setFullScreenIntent(fs,true).addAction(new Notification.Action.Builder(null,getString(R.string.snooze),sn).build()).addAction(new Notification.Action.Builder(null,getString(R.string.dismiss),di).build()).build();}
 private PendingIntent action(long id,String action,int salt){return PendingIntent.getBroadcast(this,code(id)^salt,new Intent(this,AlarmReceiver.class).setAction(action).putExtra(AlarmIntentActions.EXTRA_ID,id),PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE);}
 private void play(Alarm a){if(!"silent".equals(a.ringtone)){try{Uri uri=a.ringtone.isEmpty()?Settings.System.DEFAULT_ALARM_ALERT_URI:Uri.parse(a.ringtone);player=new MediaPlayer();player.setAudioAttributes(new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build());player.setDataSource(this,uri);player.setLooping(true);player.prepare();if(a.gradualVolume){player.setVolume(.08f,.08f);player.start();volumeHandler=new Handler(Looper.getMainLooper());for(int step=1;step<=10;step++){final float v=Math.min(1f,.08f+step*.092f);volumeHandler.postDelayed(()->{if(player!=null)player.setVolume(v,v);},step*3000L);}}else player.start();}catch(Exception ignored){}}if(a.vibrate){vib=getSystemService(Vibrator.class);if(vib!=null)vib.vibrate(VibrationEffect.createWaveform(new long[]{0,700,350,700},0));}}
 private void stopPlayback(){playingId=-1;if(volumeHandler!=null){volumeHandler.removeCallbacksAndMessages(null);volumeHandler=null;}if(player!=null){try{player.stop();}catch(Exception ignored){}player.release();player=null;}if(vib!=null){vib.cancel();vib=null;}}
 @Override public void onDestroy(){synchronized(AlarmService.class){ringing.clear();}stopPlayback();stopForeground(STOP_FOREGROUND_REMOVE);super.onDestroy();}@Override public IBinder onBind(Intent i){return null;}private static int code(long id){return (int)(id^(id>>>32));}private static int notificationId(long id){return 1000+(int)(Math.abs(id)%10000);}
}