import AVFoundation
import Foundation

protocol AudioCaptureCoordinatorDelegate: AnyObject {
    func didFinishRecordingAudio(_ output: URL?)
    func didUpdateAudioConfiguration(_ result: AudioCaptureCoordinator.SessionSetupResult)
}

class AudioCaptureCoordinator: NSObject, ObservableObject {
    private var audioRecorder: AVAudioRecorder?
    private var recordingSession: AVAudioSession?
    private var outputURL: URL?

    enum SessionSetupResult {
        case notStarted
        case success
        case notAuthorized
        case configurationFailed
    }

    weak var delegate: AudioCaptureCoordinatorDelegate?

    // Initializes the audio recording session
    override init() {
        super.init()
        configureAudioSession()
    }

    // Configures the audio session for recording
    private func configureAudioSession() {
        recordingSession = AVAudioSession.sharedInstance()
        do {
            try recordingSession?.setCategory(.playAndRecord, mode: .default)
            try recordingSession?.setActive(true, options: .notifyOthersOnDeactivation)
        } catch {
            print("Failed to set up audio session: \(error.localizedDescription)")
        }
    }

    func resetAudioSessionForPlayback() {
        DispatchQueue.main.async {
            do {
                let session = AVAudioSession.sharedInstance()
                try session.setCategory(.playback)
                try session.setActive(true)
            } catch {
                print("Error resetting audio session: \(error)")
            }
        }
    }

    func configure() {
        checkMicrophoneAuthorization()
    }

    // Checks and requests microphone authorization
    func checkMicrophoneAuthorization() {
        AVAudioApplication.requestRecordPermission { granted in
            DispatchQueue.main.async { [weak self] in
                if granted {
                    guard let randomFileURL = Adamantium.createRandomFileURLInDocuments("mp4") else { return }
                    self?.outputURL = randomFileURL
                    self?.prepareToRecord(to: randomFileURL)
                } else {
                    self?.delegate?.didUpdateAudioConfiguration(.notAuthorized)
                }
            }
        }
    }

    // Starts recording audio and saves it to the specified URL
    func prepareToRecord(to url: URL) {
        let settings: [String: Any] = [
            AVFormatIDKey: kAudioFormatMPEG4AAC,
            AVSampleRateKey: 44100,
            AVNumberOfChannelsKey: 2,
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
        ]

        do {
            audioRecorder = try AVAudioRecorder(url: url, settings: settings)
            audioRecorder?.delegate = self
            audioRecorder?.prepareToRecord()
            delegate?.didUpdateAudioConfiguration(.success)
        } catch {
            print("Failed to start recording: \(error.localizedDescription)")
            delegate?.didUpdateAudioConfiguration(.configurationFailed)
        }
    }

    func startRecordingIfNeeded() {
        guard !isRecording else { return }
        audioRecorder?.record()
    }

    // Stops recording audio
    func stopRecording() {
        guard isRecording else {
            print("No recording in progress")
            return
        }
        audioRecorder?.stop()
        resetAudioSessionForPlayback()
    }

    // Checks if the recorder is currently recording
    var isRecording: Bool {
        return audioRecorder?.isRecording ?? false
    }
}

// Conforming to AVAudioRecorderDelegate to handle events (optional)
extension AudioCaptureCoordinator: AVAudioRecorderDelegate {
    func audioRecorderDidFinishRecording(_: AVAudioRecorder, successfully flag: Bool) {
        if flag {
            delegate?.didFinishRecordingAudio(outputURL)
        } else {
            print("Recording failed to finish successfully")
        }
    }

    func audioRecorderEncodeErrorDidOccur(_: AVAudioRecorder, error: Error?) {
        if let error = error {
            print("Recording encode error: \(error.localizedDescription)")
        }
    }
}
