import Foundation
import AVFoundation

// MARK: - Tone Generator

/// Generates audio tones (sine waves) for musical notes.
/// Uses AVAudioEngine with an AVAudioSourceNode for real-time synthesis.
class ToneGenerator {

    // MARK: - Properties

    private let sampleRate: Double
    private var phase: Double = 0.0
    private var currentFrequency: Double = 0.0
    private var targetFrequency: Double = 0.0
    var amplitude: Double = 0.3
    private var isActive: Bool = false

    // Envelope for smoother note transitions
    private var envelopePhase: EnvelopePhase = .idle
    private var envelopeLevel: Double = 0.0
    private let attackTime: Double = 0.01   // 10ms attack
    private let releaseTime: Double = 0.02  // 20ms release

    enum EnvelopePhase {
        case idle, attack, sustain, release
    }

    // MARK: - Initialization

    init(sampleRate: Double = AppConstants.sampleRate) {
        self.sampleRate = sampleRate
    }

    // MARK: - Control

    /// Start playing a tone at the given frequency
    func noteOn(frequency: Double) {
        targetFrequency = frequency
        currentFrequency = frequency
        isActive = true
        envelopePhase = .attack
    }

    /// Stop the current tone
    func noteOff() {
        envelopePhase = .release
    }

    /// Immediately silence (no release)
    func silence() {
        isActive = false
        envelopePhase = .idle
        envelopeLevel = 0.0
    }

    // MARK: - Audio generation

    /// Generate audio samples into a buffer.
    /// Called by AVAudioSourceNode's render block.
    func generateSamples(buffer: UnsafeMutablePointer<Float>, frameCount: Int) {
        let twoPi = 2.0 * Double.pi
        let attackIncrement = 1.0 / (attackTime * sampleRate)
        let releaseIncrement = 1.0 / (releaseTime * sampleRate)

        for i in 0..<frameCount {
            // Update envelope
            switch envelopePhase {
            case .idle:
                envelopeLevel = 0.0
            case .attack:
                envelopeLevel += attackIncrement
                if envelopeLevel >= 1.0 {
                    envelopeLevel = 1.0
                    envelopePhase = .sustain
                }
            case .sustain:
                envelopeLevel = 1.0
            case .release:
                envelopeLevel -= releaseIncrement
                if envelopeLevel <= 0.0 {
                    envelopeLevel = 0.0
                    envelopePhase = .idle
                    isActive = false
                }
            }

            // Generate sine wave
            let sample: Float
            if isActive || envelopePhase == .release {
                let value = sin(phase * twoPi) * amplitude * envelopeLevel
                sample = Float(value)
                phase += currentFrequency / sampleRate
                if phase >= 1.0 { phase -= 1.0 }
            } else {
                sample = 0.0
            }

            buffer[i] = sample
        }
    }

    /// Create an AVAudioSourceNode that generates tones
    func createSourceNode(format: AVAudioFormat) -> AVAudioSourceNode {
        return AVAudioSourceNode(format: format) { [weak self] _, _, frameCount, audioBufferList -> OSStatus in
            guard let self = self else { return noErr }

            let bufferList = UnsafeMutableAudioBufferListPointer(audioBufferList)
            guard let buffer = bufferList.first?.mData?.assumingMemoryBound(to: Float.self) else {
                return noErr
            }

            self.generateSamples(buffer: buffer, frameCount: Int(frameCount))

            // Copy to all channels if needed
            for i in 1..<bufferList.count {
                if let dest = bufferList[i].mData?.assumingMemoryBound(to: Float.self) {
                    memcpy(dest, buffer, Int(frameCount) * MemoryLayout<Float>.size)
                }
            }

            return noErr
        }
    }
}
