package com.babysitter.app;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;

import java.io.File;

/**
 * שירות רקע שרץ במכשיר שנשאר בחדר הילדים.
 * לא שולח שום דבר לשרת ולא ל-AI חיצוני - כל הבדיקה (עוצמת קול) נעשית
 * מקומית על המכשיר עצמו (MediaRecorder.getMaxAmplitude), ולכן זה עובד
 * לגמרי אופליין. כשהעוצמה עוברת סף מסוים - מתבצעת שיחה רגילה (ACTION_CALL)
 * למספר שהוגדר.
 */
public class CryDetectionService extends Service {

    private static final String CHANNEL_ID = "babysitter_channel";
    private static final int NOTIFICATION_ID = 1;

    // כל כמה מילישניות בודקים את עוצמת הקול
    private static final long SAMPLE_INTERVAL_MS = 700;

    // אחרי שיחה - כמה זמן לא להתקשר שוב (כדי לא לחייג שוב ושוב ברצף)
    private static final long CALL_COOLDOWN_MS = 60_000;

    // כל כמה זמן להפעיל מחדש את ההקלטה, כדי שקובץ ההקלטה הזמני לא יתפח
    // לגודל בלתי מוגבל (חשוב במיוחד במכשיר ישן עם מקום אחסון מוגבל, כשהאפליקציה
    // רצה ברצף שעות ארוכות בלילה)
    private static final long RECORDER_RESTART_INTERVAL_MS = 4 * 60_000;

    // אחרי כמה כשלונות רצופים בהכנת ההקלטה, ננסה שוב בהפרש הזה
    private static final long RETRY_INTERVAL_MS = 3_000;

    private MediaRecorder recorder;
    private Handler handler;
    private Runnable sampleRunnable;
    private Runnable restartRunnable;
    private PowerManager.WakeLock wakeLock;

    private String phoneNumber;
    private int sensitivityPercent; // 0-100 מהמשתמש, 0=רגיש מאוד, 100=רגיש הכי פחות
    private long lastCallTimeMs = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        handler = new Handler(Looper.getMainLooper());
        createNotificationChannelIfNeeded();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        SharedPreferences prefs = getSharedPreferences(MainActivity.PREFS_NAME, MODE_PRIVATE);
        phoneNumber = prefs.getString(MainActivity.KEY_PHONE, "");
        sensitivityPercent = prefs.getInt(MainActivity.KEY_SENSITIVITY, 40);

        startForeground(NOTIFICATION_ID, buildNotification());
        acquireWakeLock();
        startRecordingAndMonitoring();
        scheduleRecorderRestart();

        // אם השירות נהרג ע"י המערכת - שיתחיל מחדש עם אותם נתונים (ה-Intent האחרון)
        return START_REDELIVER_INTENT;
    }

    private void scheduleRecorderRestart() {
        if (restartRunnable != null) {
            handler.removeCallbacks(restartRunnable);
        }
        restartRunnable = new Runnable() {
            @Override
            public void run() {
                startRecordingAndMonitoring();
                handler.postDelayed(this, RECORDER_RESTART_INTERVAL_MS);
            }
        };
        handler.postDelayed(restartRunnable, RECORDER_RESTART_INTERVAL_MS);
    }

    private void startRecordingAndMonitoring() {
        // מנקים לולאות דגימה קודמות כדי לא ליצור כפילויות בכל הפעלה מחדש
        if (sampleRunnable != null) {
            handler.removeCallbacks(sampleRunnable);
        }
        stopRecorderQuietly();

        // לא שומרים את ההקלטה עצמה בכלל - רק בודקים עוצמה. הקובץ נמחק ונוצר
        // מחדש בכל מחזור כדי שלא יתפח לגודל בלתי מוגבל.
        File tempFile = new File(getCacheDir(), "monitor.3gp");
        if (tempFile.exists()) {
            tempFile.delete();
        }

        try {
            recorder = new MediaRecorder();
            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            recorder.setOutputFile(tempFile.getAbsolutePath());
            recorder.setOnErrorListener((mr, what, extra) -> {
                // למשל אם המיקרופון נתפס ע"י שיחה פעילה - ננסה שוב בעוד קצת זמן
                stopRecorderQuietly();
                handler.postDelayed(this::startRecordingAndMonitoring, RETRY_INTERVAL_MS);
            });
            recorder.prepare();
            recorder.start();
        } catch (Exception e) {
            // ההקלטה נכשלה (למשל המיקרופון תפוס בשיחה) - ננסה שוב בעוד קצת זמן
            stopRecorderQuietly();
            handler.postDelayed(this::startRecordingAndMonitoring, RETRY_INTERVAL_MS);
            return;
        }

        sampleRunnable = new Runnable() {
            @Override
            public void run() {
                checkAmplitude();
                handler.postDelayed(this, SAMPLE_INTERVAL_MS);
            }
        };
        handler.postDelayed(sampleRunnable, SAMPLE_INTERVAL_MS);
    }

    private void checkAmplitude() {
        if (recorder == null) return;
        int amplitude;
        try {
            amplitude = recorder.getMaxAmplitude();
        } catch (Exception e) {
            return;
        }

        // הסף בפועל: ככל שהרגישות (sensitivityPercent) נמוכה יותר, כך הסף נמוך יותר
        // כלומר יותר רגיש לרעשים חלשים. טווח סביר לרעש חדר: 0-15000.
        int threshold = 1500 + (sensitivityPercent * 130); // ~1500 עד ~14500

        if (amplitude > threshold) {
            tryPlaceCall();
        }
    }

    private void tryPlaceCall() {
        long now = System.currentTimeMillis();
        if (now - lastCallTimeMs < CALL_COOLDOWN_MS) {
            return; // בקירור - לא מתקשרים שוב מיד
        }
        if (phoneNumber == null || phoneNumber.isEmpty()) {
            return;
        }
        lastCallTimeMs = now;

        Intent callIntent = new Intent(Intent.ACTION_CALL);
        callIntent.setData(Uri.parse("tel:" + phoneNumber));
        callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            startActivity(callIntent);
        } catch (SecurityException se) {
            // אין הרשאת שיחה - נופלים חזרה למסך חיוג רגיל (ידרוש לחיצה ידנית)
            Intent dialIntent = new Intent(Intent.ACTION_DIAL);
            dialIntent.setData(Uri.parse("tel:" + phoneNumber));
            dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(dialIntent);
        }
    }

    private void acquireWakeLock() {
        if (wakeLock != null && wakeLock.isHeld()) {
            return;
        }
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (pm != null) {
            wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BabySitter::MonitorLock");
            wakeLock.acquire();
        }
    }

    private void releaseWakeLock() {
        if (wakeLock != null && wakeLock.isHeld()) {
            wakeLock.release();
        }
    }

    private void stopRecorderQuietly() {
        if (recorder != null) {
            try {
                recorder.stop();
            } catch (Exception ignored) {
            }
            try {
                recorder.release();
            } catch (Exception ignored) {
            }
            recorder = null;
        }
    }

    private void createNotificationChannelIfNeeded() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID, getString(R.string.notification_title),
                    NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }
    }

    @SuppressWarnings("deprecation")
    private Notification buildNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return new Notification.Builder(this, CHANNEL_ID)
                    .setContentTitle(getString(R.string.notification_title))
                    .setContentText(getString(R.string.notification_text))
                    .setSmallIcon(android.R.drawable.ic_btn_speak_now)
                    .setOngoing(true)
                    .build();
        } else {
            // בנאי הפרמטר-היחיד מיועד ל-API ישן יותר (כמו API 19 שאליו מכוונת
            // האפליקציה) - הוא deprecated רק ב-API חדשות יותר, שם ממילא נכנסים לענף הראשון.
            return new Notification.Builder(this)
                    .setContentTitle(getString(R.string.notification_title))
                    .setContentText(getString(R.string.notification_text))
                    .setSmallIcon(android.R.drawable.ic_btn_speak_now)
                    .setOngoing(true)
                    .build();
        }
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (sampleRunnable != null) handler.removeCallbacks(sampleRunnable);
        if (restartRunnable != null) handler.removeCallbacks(restartRunnable);
        stopRecorderQuietly();
        releaseWakeLock();
        getSharedPreferences(MainActivity.PREFS_NAME, MODE_PRIVATE)
                .edit().putBoolean(MainActivity.KEY_RUNNING, false).apply();
    }
}
