import ExpoModulesCore
import AVFoundation

public class MetronomeModule: Module {
    var bpm: Int = 120
    var isRunning: Bool = false
    var audioPlayer: AVAudioPlayer?
    var timer: DispatchSourceTimer?
    
    public func definition() -> ModuleDefinition {
        Name("Metronome")
          
        Function("setBpm") { (bpm: Int) -> Void in
            self.bpm = bpm
            
            if (isRunning) {
                stop()
                start()
            }
        }
        
        Function("start") {
            start()
        }
        
        Function("stop") {
            stop()
        }
        
        OnCreate {
            loadSound()
        }
        
        OnDestroy {
            timer?.cancel()
            audioPlayer?.stop()
        }
    }
    
    func start() {
        if isRunning { return }
        
        isRunning = true
        playSound()
        
        let interval = 60.0 / Double(bpm)
        
        timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global(qos: .utility))
        timer?.schedule(deadline: .now(), repeating: interval)
        
        timer?.setEventHandler { [weak self] in
            self?.playSound()
        }
        
        timer?.resume()
    }
    
    func stop() {
        isRunning = false
        timer?.cancel()
    }
    
    func playSound() {
        audioPlayer?.play()
    }
    
    private func loadSound() {
        let bundle = Bundle(for: MetronomeModule.self)
        guard let resourceBundleURL = bundle.url(forResource: "MetronomeResources", withExtension: "bundle") else { return }
        guard let resourceBundle = Bundle(url: resourceBundleURL) else { return }
        guard let soundURL = resourceBundle.url(forResource: "low", withExtension: "wav") else { return }
                
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
            audioPlayer?.prepareToPlay()
        } catch {
            return
        }
    }
}
