import AVFoundation
import Foundation
import MastermindPOCCore

enum MicrophonePCMConverter {
    static func extractFrame(from buffer: AVAudioPCMBuffer) -> PCMFrame? {
        let frameCount = Int(buffer.frameLength)
        guard frameCount > 0 else {
            return nil
        }

        let channelCount = max(1, Int(buffer.format.channelCount))
        let sourceRate = Int(buffer.format.sampleRate.rounded())
        let samples: [Float]

        if let floatData = buffer.floatChannelData {
            samples = mixFloatChannels(floatData, channelCount: channelCount, frameCount: frameCount)
        } else if let int16Data = buffer.int16ChannelData {
            samples = mixInt16Channels(int16Data, channelCount: channelCount, frameCount: frameCount)
        } else {
            return nil
        }

        let mono16k = PCM16LE.resampleLinear(samples: samples, sourceRate: sourceRate, targetRate: 16_000)
        let data = PCM16LE.encode(samples: mono16k)

        return PCMFrame(source: .microphone, sampleRate: 16_000, channels: 1, pcmS16LE: data)
    }

    private static func mixFloatChannels(_ channelData: UnsafePointer<UnsafeMutablePointer<Float>>, channelCount: Int, frameCount: Int) -> [Float] {
        var mono = [Float](repeating: 0, count: frameCount)
        let divisor = Float(channelCount)

        for channel in 0..<channelCount {
            let channelPointer = channelData[channel]
            for frame in 0..<frameCount {
                mono[frame] += channelPointer[frame] / divisor
            }
        }

        return mono
    }

    private static func mixInt16Channels(_ channelData: UnsafePointer<UnsafeMutablePointer<Int16>>, channelCount: Int, frameCount: Int) -> [Float] {
        var mono = [Float](repeating: 0, count: frameCount)
        let divisor = Float(channelCount)

        for channel in 0..<channelCount {
            let channelPointer = channelData[channel]
            for frame in 0..<frameCount {
                mono[frame] += (Float(channelPointer[frame]) / Float(Int16.max)) / divisor
            }
        }

        return mono
    }
}
