package com.example.polaritychecker

import android.annotation.SuppressLint
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import kotlinx.coroutines.*
import kotlin.math.abs
import kotlin.math.log10

class AudioAnalyzer(
    private val onLevelUpdate: (Float) -> Unit,
    private val onPolarityDetected: (Boolean) -> Unit
) {
    private var audioRecord: AudioRecord? = null
    private var isRecording = false
    private var job: Job? = null
    private val sampleRate = 48000
    private val bufferSize = AudioRecord.getMinBufferSize(
        sampleRate,
        AudioFormat.CHANNEL_IN_MONO,
        AudioFormat.ENCODING_PCM_16BIT
    ) * 2

    var thresholdDb = -17.0f
    
    private var lastTriggerTimeMs = 0L
    private val triggerHoldoffMs = 300L

    @SuppressLint("MissingPermission")
    fun start() {
        if (isRecording) return
        isRecording = true

        audioRecord = AudioRecord(
            MediaRecorder.AudioSource.UNPROCESSED,
            sampleRate,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            bufferSize
        )

        if (audioRecord?.state != AudioRecord.STATE_INITIALIZED) {
            audioRecord?.release()
            audioRecord = AudioRecord(
                MediaRecorder.AudioSource.VOICE_RECOGNITION,
                sampleRate,
                AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT,
                bufferSize
            )
        }

        audioRecord?.startRecording()

        job = CoroutineScope(Dispatchers.IO).launch {
            val buffer = ShortArray(bufferSize)
            while (isActive && isRecording) {
                val read = audioRecord?.read(buffer, 0, buffer.size) ?: 0
                if (read > 0) {
                    processAudioBuffer(buffer.copyOfRange(0, read))
                }
            }
        }
    }

    private fun processAudioBuffer(buffer: ShortArray) {
        var maxAbs = 0.0f
        var maxSampleIndex = -1
        
        for (i in buffer.indices) {
            val sampleAbs = abs(buffer[i].toFloat())
            if (sampleAbs > maxAbs) {
                maxAbs = sampleAbs
                maxSampleIndex = i
            }
        }

        val dbfs = if (maxAbs > 0) {
            20 * log10(maxAbs / 32767.0f)
        } else {
            -60.0f
        }

        onLevelUpdate(dbfs)

        if (dbfs >= thresholdDb) {
            val currentTime = System.currentTimeMillis()
            if (currentTime - lastTriggerTimeMs > triggerHoldoffMs) {
                val peakSample = buffer[maxSampleIndex]
                val isPositive = peakSample > 0
                
                onPolarityDetected(isPositive)
                lastTriggerTimeMs = currentTime
            }
        }
    }

    fun stop() {
        isRecording = false
        job?.cancel()
        audioRecord?.stop()
        audioRecord?.release()
        audioRecord = null
    }
}
