//
//  SoundManager.swift
//  SodaLive
//
//  Created by klaus on 2023/08/10.
//

import Foundation
import AVKit

class SoundManager: NSObject, ObservableObject {
    @Published var errorMessage = ""
    @Published var isShowPopup = false
    @Published var isLoading = false
    @Published var onClose = false
    
    @Published var isPlaying = false
    @Published var isRecording = false
    @Published var duration: TimeInterval = 0
    
    var player: AVAudioPlayer!
    var audioRecorder: AVAudioRecorder!
    
    var startTimer: (() -> Void)?
    var stopTimer: (() -> Void)?
    
    func prepareRecording() {
        isLoading = true
        
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playAndRecord, mode: .default)
            try audioSession.setActive(true)
            audioSession.requestRecordPermission() { [weak self] allowed in
                DispatchQueue.main.async {
                    if !allowed {
                        self?.errorMessage = "권한을 허용하지 않으시면 음성메시지 서비스를 이용하실 수 없습니다."
                        self?.isShowPopup = true
                        self?.onClose = true
                    }
                }
            }
        } catch {
            errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
            isShowPopup = true
            onClose = true
        }
        
        isLoading = false
    }
    
    func startRecording() {
        let settings = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 12000,
            AVNumberOfChannelsKey: 1,
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
        ]
        
        do {
            audioRecorder = try AVAudioRecorder(url: getAudioFileURL(), settings: settings)
            audioRecorder.record()
            
            if let startTimer = startTimer {
                startTimer()
            }
            isRecording = true
        } catch {
            errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
            isShowPopup = true
        }
    }
    
    func stopRecording() {
        audioRecorder.stop()
        audioRecorder = nil
        isRecording = false
        
        if let stopTimer = stopTimer {
            stopTimer()
        }
        
        prepareForPlay()
    }
    
    func getRecorderCurrentTime() -> TimeInterval {
        return audioRecorder.currentTime
    }
    
    func prepareForPlay(_ url: URL? = nil) {
        isLoading = true
        
        DispatchQueue.main.async {
            let audioSession = AVAudioSession.sharedInstance()
            do {
                try audioSession.setCategory(.playback, mode: .default)
                
                if let url = url {
                    self.player = try AVAudioPlayer(data: Data(contentsOf: url))
                } else {
                    self.player = try AVAudioPlayer(contentsOf: self.getAudioFileURL())
                }
                
                self.player?.volume = 1
                self.player?.delegate = self
                self.player?.prepareToPlay()
                
                self.duration = self.player.duration
            } catch {
                self.errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
                self.isShowPopup = true
            }
            
            self.isLoading = false
        }
    }
    
    func playAudio() {
        player?.play()
        
        isPlaying = player.isPlaying
        if let startTimer = startTimer {
            startTimer()
        }
    }
    
    func stopAudio() {
        player.stop()
        player.currentTime = 0
        isPlaying = player.isPlaying
        if let stopTimer = stopTimer {
            stopTimer()
        }
    }
    
    func getPlayerCurrentTime() -> TimeInterval {
        return player.currentTime
    }
    
    func deleteAudioFile() {
        do {
            try FileManager.default.removeItem(at: getAudioFileURL())
            duration = 0
        } catch {
            errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
            isShowPopup = true
        }
    }
    
    func getAudioFileURL() -> URL {
        return getDocumentsDirectory().appendingPathComponent("recording.m4a")
    }
    
    private func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
}

extension SoundManager: AVAudioPlayerDelegate {
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        stopAudio()
    }
}