package com.qsjnic.demo.radio;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.media.AudioAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.qsjnic.mcu.contract.RadioState;
import com.qsjnic.mcu.sdk.McuClient;
import com.qsjnic.mcu.sdk.McuRadioClient;
import com.qsjnic.mcu.sdk.RadioListener;

/**
 * Radio Demo with FM Tuner audio passthrough.
 */
public class MainActivity extends Activity {

    private static final String TAG = "RadioDemo";
    private static final int PERMISSION_REQ = 100;

    private final Handler ui = new Handler(Looper.getMainLooper());

    // Data panel
    private TextView tvBand, tvFreq, tvFreqMhz, tvSignal, tvStereo, tvSeek, tvAudioStatus;

    // Control buttons
    private TextView tvStatus;
    private Button btnFm, btnAm, btn875, btn900, btnSeekFw, btnSeekStop, btnPlay875;
    private Button btnAudioStart, btnAudioStop;

    private final RadioListener listener = new RadioListener() {
        @Override public void onFreqChanged(RadioState s) {
            ui.post(() -> updateRadio(s));
        }
        @Override public void onPsPty(int pi, int pty, String ps) {
            Log.i(TAG, "PS/PTY pi=" + pi + " pty=" + pty + " ps=" + ps);
        }
        @Override public void onRadioText(String rt) {
            Log.i(TAG, "RT=" + rt);
        }
        @Override public void onWorkStatus(int status) {
            Log.i(TAG, "WorkStatus=" + status);
        }
    };

    // ----- Audio passthrough -----
    private AudioRecord audioRecord;
    private AudioTrack audioTrack;
    private Thread audioThread;
    private volatile boolean audioRunning = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ScrollView scroll = new ScrollView(this);
        LinearLayout root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
        root.setPadding(32, 32, 32, 32);
        root.setBackgroundColor(Color.parseColor("#F5F5F5"));

        // ===== Title =====
        TextView title = new TextView(this);
        title.setText("Radio Tuner + Audio");
        title.setTextSize(24f);
        title.setTypeface(null, Typeface.BOLD);
        title.setTextColor(Color.parseColor("#333333"));
        title.setPadding(0, 0, 0, 16);
        root.addView(title);

        tvStatus = new TextView(this);
        tvStatus.setText("Service: connecting");
        tvStatus.setTextSize(14f);
        tvStatus.setTextColor(Color.parseColor("#555555"));
        tvStatus.setPadding(0, 0, 0, 16);
        root.addView(tvStatus);

        // ===== Frequency Display Card =====
        LinearLayout freqCard = card(root);
        tvBand = new TextView(this);
        tvBand.setText("--");
        tvBand.setTextSize(16f);
        tvBand.setTextColor(Color.parseColor("#888888"));
        tvBand.setGravity(Gravity.CENTER);
        freqCard.addView(tvBand);

        tvFreq = new TextView(this);
        tvFreq.setText("----");
        tvFreq.setTextSize(56f);
        tvFreq.setTypeface(null, Typeface.BOLD);
        tvFreq.setTextColor(Color.parseColor("#1976D2"));
        tvFreq.setGravity(Gravity.CENTER);
        freqCard.addView(tvFreq);

        tvFreqMhz = new TextView(this);
        tvFreqMhz.setText("MHz");
        tvFreqMhz.setTextSize(14f);
        tvFreqMhz.setTextColor(Color.parseColor("#888888"));
        tvFreqMhz.setGravity(Gravity.CENTER);
        freqCard.addView(tvFreqMhz);

        LinearLayout detailRow = new LinearLayout(this);
        detailRow.setOrientation(LinearLayout.HORIZONTAL);
        detailRow.setGravity(Gravity.CENTER);
        detailRow.setPadding(0, 16, 0, 0);
        freqCard.addView(detailRow);

        tvSignal = chip(detailRow, "Signal: --");
        tvStereo = chip(detailRow, "Stereo: --");
        tvSeek   = chip(detailRow, "Seek: --");

        // ===== Audio Status =====
        root.addView(sectionTitle("Tuner Audio"));
        LinearLayout audioCard = card(root);
        tvAudioStatus = new TextView(this);
        tvAudioStatus.setText("Audio: stopped");
        tvAudioStatus.setTextSize(14f);
        tvAudioStatus.setTextColor(Color.parseColor("#555555"));
        tvAudioStatus.setPadding(0, 8, 0, 8);
        audioCard.addView(tvAudioStatus);

        LinearLayout audioRow = buttonRow(audioCard);
        btnAudioStart = btn(audioRow, "Start Audio", v -> startTunerAudio());
        btnAudioStop  = btn(audioRow, "Stop Audio",  v -> stopTunerAudio());

        // ===== Band Selection =====
        root.addView(sectionTitle("Band"));
        LinearLayout bandCard = card(root);
        LinearLayout bandRow = buttonRow(bandCard);
        btnFm = btn(bandRow, "FM", v -> McuClient.getInstance().radio().setBand(McuRadioClient.BAND_FM));
        btnAm = btn(bandRow, "AM", v -> McuClient.getInstance().radio().setBand(McuRadioClient.BAND_AM));

        // ===== Frequency Presets =====
        root.addView(sectionTitle("Frequency"));
        LinearLayout freqCtrlCard = card(root);
        LinearLayout freqRow1 = buttonRow(freqCtrlCard);
        btn875 = btn(freqRow1, "87.5 MHz", v -> McuClient.getInstance().radio().setFrequency(8750));
        btn900 = btn(freqRow1, "90.0 MHz", v -> McuClient.getInstance().radio().setFrequency(9000));

        // ===== Seek Control =====
        root.addView(sectionTitle("Seek"));
        LinearLayout seekCard = card(root);
        LinearLayout seekRow = buttonRow(seekCard);
        btnSeekFw   = btn(seekRow, "Forward",  v -> McuClient.getInstance().radio().seekForward());
        btnSeekStop = btn(seekRow, "Stop",     v -> McuClient.getInstance().radio().seekStop());

        // ===== Other =====
        root.addView(sectionTitle("Other"));
        LinearLayout otherCard = card(root);
        LinearLayout otherRow = buttonRow(otherCard);
        btnPlay875 = btn(otherRow, "Play 90.0", v -> playFm900());
        btn(otherRow, "Ant ON",  v -> McuClient.getInstance().radio().setAntPower(true));
        btn(otherRow, "Init Range", v -> McuClient.getInstance().radio().setFreqRange(0, 522, 1670, 8750, 10800, 9, 1));

        scroll.addView(root);
        setContentView(scroll);

        McuClient.getInstance().init(getApplicationContext());
        McuClient.getInstance().addReadyListener(() -> ui.post(() -> {
            tvStatus.setText("Service: connected, linkAlive=" + McuClient.getInstance().isLinkAlive());
            playFm900();
            ui.postDelayed(this::startTunerAudio, 1000);
        }));
        McuClient.getInstance().radio().addListener(listener);

        // Request audio permission
        if (checkSelfPermission(android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{android.Manifest.permission.RECORD_AUDIO}, PERMISSION_REQ);
        }
    }

    // ---------- Audio Passthrough ----------

    private void startTunerAudio() {
        if (audioRunning) return;

        AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
        AudioDeviceInfo tunerDevice = null;
        for (AudioDeviceInfo dev : am.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
            Log.i(TAG, "Input device: type=" + dev.getType() + " name=" + dev.getProductName());
            if (dev.getType() == AudioDeviceInfo.TYPE_FM_TUNER) {
                tunerDevice = dev;
                break;
            }
        }

        if (tunerDevice == null) {
            tvAudioStatus.setText("Audio: FM Tuner device NOT FOUND");
            Log.e(TAG, "TYPE_FM_TUNER not found in input devices");
            return;
        }

        tvAudioStatus.setText("Audio: starting...");
        Log.i(TAG, "Found FM Tuner: " + tunerDevice.getProductName());

        final int sampleRate = 48000;
        final int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
        final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        final int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
        final int bufferSize = Math.max(minBufSize, 16384);
        // AUDIO_SOURCE_FM_TUNER = 1998 (from system/audio.h)
        final int AUDIO_SOURCE_FM_TUNER = 1998;

        try {
            // Use DEFAULT source + setPreferredDevice(tuner) approach
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT,
                    sampleRate, channelConfig, audioFormat, bufferSize);

            // Try to set device on API 24+
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && audioRecord.setPreferredDevice(tunerDevice)) {
                Log.i(TAG, "setPreferredDevice(tuner) succeeded");
            }

            audioTrack = new AudioTrack.Builder()
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .build())
                    .setAudioFormat(new AudioFormat.Builder()
                            .setSampleRate(sampleRate)
                            .setEncoding(audioFormat)
                            .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                            .build())
                    .setBufferSizeInBytes(bufferSize)
                    .setTransferMode(AudioTrack.MODE_STREAM)
                    .build();

            audioRecord.startRecording();
            audioTrack.play();
            audioRunning = true;

            final int playbackBufSize = bufferSize;
            audioThread = new Thread(() -> {
                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
                byte[] buf = new byte[playbackBufSize];
                int totalRead = 0;
                long lastLog = System.currentTimeMillis();
                while (audioRunning) {
                    int read = audioRecord.read(buf, 0, buf.length);
                    if (read > 0) {
                        totalRead += read;
                        audioTrack.write(buf, 0, read);
                        // Log first non-zero sample every 3 seconds
                        long now = System.currentTimeMillis();
                        if (now - lastLog > 3000) {
                            short sample = (short) ((buf[0] & 0xFF) | ((buf[1] & 0xFF) << 8));
                            Log.i(TAG, "Audio passthrough: read=" + read
                                    + " total=" + totalRead
                                    + " sample=" + sample
                                    + " trackState=" + audioTrack.getPlayState());
                            lastLog = now;
                        }
                    } else if (read < 0) {
                        Log.e(TAG, "AudioRecord read error: " + read);
                        break;
                    }
                }
            }, "TunerAudio");
            audioThread.setPriority(Thread.MAX_PRIORITY);
            audioThread.start();

            tvAudioStatus.setText("Audio: PLAYING (" + tunerDevice.getProductName() + ")");
            tvAudioStatus.setTextColor(Color.parseColor("#4CAF50"));

        } catch (Exception e) {
            Log.e(TAG, "startTunerAudio failed", e);
            tvAudioStatus.setText("Audio: FAILED - " + e.getMessage());
            tvAudioStatus.setTextColor(Color.parseColor("#F44336"));
            stopTunerAudio();
        }
    }

    private void stopTunerAudio() {
        audioRunning = false;
        if (audioThread != null) {
            try { audioThread.join(500); } catch (InterruptedException ignored) {}
            audioThread = null;
        }
        if (audioRecord != null) {
            try { audioRecord.stop(); } catch (Exception ignored) {}
            try { audioRecord.release(); } catch (Exception ignored) {}
            audioRecord = null;
        }
        if (audioTrack != null) {
            try { audioTrack.stop(); } catch (Exception ignored) {}
            try { audioTrack.release(); } catch (Exception ignored) {}
            audioTrack = null;
        }
        tvAudioStatus.setText("Audio: stopped");
        tvAudioStatus.setTextColor(Color.parseColor("#555555"));
        Log.i(TAG, "Tuner audio stopped");
    }

    // ---------- UI helpers ----------

    private TextView sectionTitle(String text) {
        TextView t = new TextView(this);
        t.setText(text);
        t.setTextSize(14f);
        t.setTypeface(null, Typeface.BOLD);
        t.setTextColor(Color.parseColor("#666666"));
        t.setPadding(8, 24, 0, 8);
        return t;
    }

    private LinearLayout card(LinearLayout parent) {
        LinearLayout card = new LinearLayout(this);
        card.setOrientation(LinearLayout.VERTICAL);
        card.setPadding(24, 24, 24, 24);
        card.setBackgroundColor(Color.WHITE);
        GradientDrawable bg = new GradientDrawable();
        bg.setColor(Color.WHITE);
        bg.setCornerRadius(16f);
        card.setBackground(bg);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(0, 0, 0, 16);
        card.setLayoutParams(lp);
        parent.addView(card);
        return card;
    }

    private TextView chip(LinearLayout parent, String text) {
        TextView t = new TextView(this);
        t.setText(text);
        t.setTextSize(12f);
        t.setTextColor(Color.parseColor("#555555"));
        t.setPadding(16, 8, 16, 8);
        GradientDrawable bg = new GradientDrawable();
        bg.setColor(Color.parseColor("#E8E8E8"));
        bg.setCornerRadius(20f);
        t.setBackground(bg);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(8, 0, 8, 0);
        t.setLayoutParams(lp);
        parent.addView(t);
        return t;
    }

    private LinearLayout buttonRow(LinearLayout parent) {
        LinearLayout row = new LinearLayout(this);
        row.setOrientation(LinearLayout.HORIZONTAL);
        row.setPadding(0, 8, 0, 8);
        parent.addView(row);
        return row;
    }

    private Button btn(LinearLayout parent, String label, View.OnClickListener l) {
        Button b = new Button(this);
        b.setText(label);
        b.setOnClickListener(l);
        b.setAllCaps(false);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f);
        lp.setMargins(8, 0, 8, 0);
        b.setLayoutParams(lp);
        parent.addView(b);
        return b;
    }

    private void playFm900() {
        McuRadioClient radio = McuClient.getInstance().radio();
        int rcBand = radio.setBand(McuRadioClient.BAND_FM);
        int rcRange = radio.setFreqRange(0, 522, 1670, 8750, 10800, 9, 1);
        int rcAnt = radio.setAntPower(true);
        int rcStereo = radio.setSwitch(McuRadioClient.SWITCH_STEREO, 1);
        int rcRds = radio.setSwitch(McuRadioClient.SWITCH_RDS, 1);
        int rcMute = radio.setRegMute(false);  // 先解除静音
        int rcFreq = radio.setFrequency(9344);
        int rcStop = radio.seekStop();
        String msg = "Play 93.4 rc band=" + rcBand
                + " range=" + rcRange
                + " ant=" + rcAnt
                + " stereo=" + rcStereo
                + " rds=" + rcRds
                + " freq=" + rcFreq
                + " stop=" + rcStop
                + " muteOff=" + rcMute;
        Log.i(TAG, msg);
        tvStatus.setText(msg);
    }

    private int lastSignal = 0;
    private int strongFreq = 0;

    private void updateRadio(RadioState s) {
        String bandName = s.band == 0 ? "FM" : (s.band == 1 ? "AM" : "?");
        tvBand.setText(bandName + " Radio");

        double mhz = s.band == 0 ? s.freq / 100.0 : s.freq / 1000.0;
        tvFreq.setText(String.format("%.1f", mhz));
        tvFreqMhz.setText(s.band == 0 ? "MHz" : "KHz");

        tvSignal.setText("Signal: " + (s.signal >= 0 ? s.signal : "--"));
        tvStereo.setText(s.flagStereo == 1 ? "Stereo" : "Mono");
        tvStereo.setTextColor(s.flagStereo == 1 ? Color.parseColor("#4CAF50") : Color.parseColor("#999999"));

        String[] seekNames = {"Stop", "AMS", "Fwd", "Bwd", "PTY", "TA"};
        tvSeek.setText("Seek: " + (s.seekMode >= 0 && s.seekMode < seekNames.length ? seekNames[s.seekMode] : "--"));

        // Track strongest signal
        if (s.signal > lastSignal) {
            lastSignal = s.signal;
            strongFreq = s.freq;
            Log.i(TAG, "*** STRONG SIGNAL: " + s.freq + " signal=" + s.signal + " ***");
        }
    }

    @Override
    protected void onDestroy() {
        stopTunerAudio();
        McuClient.getInstance().radio().removeListener(listener);
        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!McuClient.getInstance().isReady()) {
            android.widget.Toast.makeText(this, "Service 未连接，5s后重试", android.widget.Toast.LENGTH_SHORT).show();
            new Handler(Looper.getMainLooper()).postDelayed(this::onResume, 5000);
        }
    }
}
