package com.secureline.voice;

import android.app.Service;
import android.content.Intent;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.IBinder;
import android.os.SystemProperties;
import android.util.Log;

public final class SecureLineCallRedirectService extends Service {
    private static final String TAG = "LemenzoCallRedirect";
    private static final int SAMPLE_RATE = 48000;
    private static final int FRAMES_10_MS = 480;
    private static final int MONITOR_MS = 150;

    static {
        System.loadLibrary("securelinevoice_redirect_jni");
    }

    private static native void nativeConfigure(
            float pitch, float formant, float variation,
            float warmth, float compression, float drive,
            float outputGain, float spectralTilt, float presence);
    private static native void nativeProcess(short[] audio, int frames, int sampleRate);

    private AudioManager mAudioManager;
    private volatile boolean mAlive;
    private volatile boolean mRunning;
    private Thread mMonitor;
    private Thread mAudioThread;
    private AudioRecord mUplinkRecord;
    private AudioTrack mInjectionTrack;
    private int mPreviousMode = AudioManager.MODE_NORMAL;

    @Override
    public void onCreate() {
        super.onCreate();
        mAudioManager = getSystemService(AudioManager.class);
        if (mAudioManager == null) {
            Log.e(TAG, "AudioManager unavailable");
            stopSelf();
            return;
        }
        mAlive = true;
        mMonitor = new Thread(this::monitorLoop, "LemenzoCallRedirectMonitor");
        mMonitor.start();
        Log.i(TAG, "service ready");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        mAlive = false;
        requestStop();
        Thread monitor = mMonitor;
        if (monitor != null) monitor.interrupt();
        super.onDestroy();
    }

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

    private static boolean voiceEnabled() {
        return SystemProperties.getBoolean("persist.audio.secureline.enabled", false);
    }

    private static float propertyFloat(String key, float fallback) {
        try {
            return Float.parseFloat(SystemProperties.get(key, Float.toString(fallback)));
        } catch (Throwable ignored) {
            return fallback;
        }
    }

    private void configureDsp() {
        nativeConfigure(
                propertyFloat("persist.audio.secureline.pitch", 1.0f),
                propertyFloat("persist.audio.secureline.formant", 1.0f),
                propertyFloat("persist.audio.secureline.variation", 0.0f),
                propertyFloat("persist.audio.secureline.warmth", 0.0f),
                propertyFloat("persist.audio.secureline.compression", 0.0f),
                propertyFloat("persist.audio.secureline.drive", 0.0f),
                propertyFloat("persist.audio.secureline.output_gain", 1.0f),
                propertyFloat("persist.audio.secureline.spectral_tilt", 0.0f),
                propertyFloat("persist.audio.secureline.presence", 0.0f));
    }

    private void monitorLoop() {
        while (mAlive) {
            try {
                boolean enabled = voiceEnabled();
                int mode = mAudioManager.getMode();
                if (enabled && !mRunning
                        && (mode == AudioManager.MODE_IN_CALL
                            || mode == AudioManager.MODE_CALL_SCREENING)) {
                    startPipeline();
                } else if (mRunning
                        && (!enabled
                            || (mode != AudioManager.MODE_IN_CALL
                                && mode != AudioManager.MODE_CALL_SCREENING
                                && mode != AudioManager.MODE_CALL_REDIRECT))) {
                    requestStop();
                }
                Thread.sleep(MONITOR_MS);
            } catch (InterruptedException ignored) {
            } catch (Throwable t) {
                Log.e(TAG, "monitor error", t);
                try { Thread.sleep(500); } catch (InterruptedException ignored) {}
            }
        }
    }

    private synchronized void startPipeline() {
        if (mRunning) return;
        mRunning = true;
        mAudioThread = new Thread(this::runPipeline, "LemenzoCallRedirectAudio");
        mAudioThread.start();
    }

    private void runPipeline() {
        String lastRefresh = null;
        try {
            if (!voiceEnabled()) return;
            if (!mAudioManager.isPstnCallAudioInterceptable()) {
                throw new UnsupportedOperationException("PSTN call audio is not interceptable");
            }

            mPreviousMode = mAudioManager.getMode();
            if (mPreviousMode != AudioManager.MODE_IN_CALL
                    && mPreviousMode != AudioManager.MODE_CALL_SCREENING) {
                throw new IllegalStateException("No redirectable PSTN call. mode=" + mPreviousMode);
            }

            int minRecordBytes = AudioRecord.getMinBufferSize(
                    SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);
            if (minRecordBytes <= 0) {
                throw new IllegalStateException("invalid AudioRecord minimum buffer=" + minRecordBytes);
            }
            int recordBufferBytes = Math.max(FRAMES_10_MS * 2 * 8, minRecordBytes * 2);

            // Open the established native PSTN uplink tap BEFORE redirect mode.
            mUplinkRecord = new AudioRecord(
                    MediaRecorder.AudioSource.VOICE_UPLINK,
                    SAMPLE_RATE,
                    AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    recordBufferBytes);
            if (mUplinkRecord.getState() != AudioRecord.STATE_INITIALIZED) {
                throw new IllegalStateException("VOICE_UPLINK AudioRecord init failed");
            }
            mUplinkRecord.startRecording();
            if (mUplinkRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
                throw new IllegalStateException("VOICE_UPLINK failed to start");
            }

            // Android converts CALL_REDIRECT to HAL CALL_SCREEN. Pixel HAL then
            // owns the native call-redirection/INCALL_TX route selection.
            mAudioManager.setMode(AudioManager.MODE_CALL_REDIRECT);
            Log.i(TAG, "redirect requested; reported mode=" + mAudioManager.getMode());

            AudioFormat injectionFormat = new AudioFormat.Builder()
                    .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                    .setSampleRate(SAMPLE_RATE)
                    .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
                    .build();
            mInjectionTrack = mAudioManager.getCallUplinkInjectionAudioTrack(injectionFormat);
            if (mInjectionTrack == null
                    || mInjectionTrack.getState() != AudioTrack.STATE_INITIALIZED) {
                throw new IllegalStateException("call uplink injection AudioTrack init failed");
            }
            mInjectionTrack.play();
            configureDsp();
            Log.i(TAG, "ACTIVE native VOICE_UPLINK -> Lemenzo DSP -> CALL_REDIRECT/INCALL_TX");

            short[] buffer = new short[FRAMES_10_MS];
            while (mAlive && mRunning && voiceEnabled()) {
                int mode = mAudioManager.getMode();
                if (mode != AudioManager.MODE_IN_CALL
                        && mode != AudioManager.MODE_CALL_SCREENING
                        && mode != AudioManager.MODE_CALL_REDIRECT) {
                    Log.i(TAG, "PSTN call ended; mode=" + mode);
                    break;
                }

                String refresh = SystemProperties.get(
                        "persist.audio.secureline.refresh", "");
                if (!refresh.equals(lastRefresh)) {
                    lastRefresh = refresh;
                    configureDsp();
                }

                int frames = mUplinkRecord.read(
                        buffer, 0, buffer.length, AudioRecord.READ_BLOCKING);
                if (frames < 0) {
                    throw new IllegalStateException("VOICE_UPLINK read failed: " + frames);
                }
                if (frames == 0) continue;

                nativeProcess(buffer, frames, SAMPLE_RATE);

                int offset = 0;
                while (offset < frames && mRunning) {
                    int written = mInjectionTrack.write(
                            buffer, offset, frames - offset, AudioTrack.WRITE_BLOCKING);
                    if (written < 0) {
                        throw new IllegalStateException("uplink injection write failed: " + written);
                    }
                    if (written == 0) {
                        Thread.yield();
                        continue;
                    }
                    offset += written;
                }
            }
        } catch (Throwable t) {
            Log.e(TAG, "redirect pipeline failed; restoring stock call", t);
        } finally {
            cleanupAndRestore();
        }
    }

    private synchronized void requestStop() {
        mRunning = false;
        AudioRecord record = mUplinkRecord;
        if (record != null) {
            try { record.stop(); } catch (Throwable ignored) {}
        }
        AudioTrack track = mInjectionTrack;
        if (track != null) {
            try { track.pause(); } catch (Throwable ignored) {}
        }
        Thread audio = mAudioThread;
        if (audio != null) audio.interrupt();
    }

    private synchronized void cleanupAndRestore() {
        AudioRecord record = mUplinkRecord;
        mUplinkRecord = null;
        if (record != null) {
            try { record.stop(); } catch (Throwable ignored) {}
            try { record.release(); } catch (Throwable ignored) {}
        }

        AudioTrack track = mInjectionTrack;
        mInjectionTrack = null;
        if (track != null) {
            try { track.pause(); } catch (Throwable ignored) {}
            try { track.flush(); } catch (Throwable ignored) {}
            try { track.stop(); } catch (Throwable ignored) {}
            try { track.release(); } catch (Throwable ignored) {}
        }

        // Restore only while Lemenzo still owns redirect mode. Never override
        // Telecom if the call already ended or another owner changed the mode.
        try {
            if (mAudioManager.getMode() == AudioManager.MODE_CALL_REDIRECT) {
                int restore = mPreviousMode;
                if (restore != AudioManager.MODE_IN_CALL
                        && restore != AudioManager.MODE_CALL_SCREENING) {
                    restore = AudioManager.MODE_IN_CALL;
                }
                mAudioManager.setMode(restore);
                Log.i(TAG, "restored stock PSTN mode=" + restore);
            }
        } catch (Throwable t) {
            Log.e(TAG, "failed restoring stock PSTN mode", t);
        }

        mAudioThread = null;
        mRunning = false;
        Log.i(TAG, "pipeline stopped");
    }
}
