//
//  TimerView.swift
//  Nextcloud Cookbook iOS Client
//
//  Created by Vincent Meilinger on 11.01.24.
//

import Foundation
import SwiftUI
import Combine
import AVFoundation
import UserNotifications


struct TimerView: View {
    @ObservedObject var timer: RecipeTimer
    
    var body: some View {
        HStack {
            Gauge(value: timer.timeTotal - timer.timeElapsed, in: 0...timer.timeTotal) {
                Text("Cooking time")
            } currentValueLabel: {
                Button {
                    if timer.isRunning {
                        timer.pause()
                    } else {
                        timer.start()
                    }
                } label: {
                    if timer.isRunning {
                        Image(systemName: "pause.fill")
                    } else {
                        Image(systemName: "play.fill")
                    }
                }
            }
            .gaugeStyle(.accessoryCircularCapacity)
            .animation(.easeInOut, value: timer.timeElapsed)
            .tint(timer.isRunning ? .green : .nextcloudBlue)
            .foregroundStyle(timer.isRunning ? Color.green : Color.nextcloudBlue)
            
            VStack(alignment: .leading) {
                Text("Cooking")
                Text(timer.duration.toTimerText())
            }
            .padding(.horizontal)
            
            Button {
                timer.cancel()
            } label: {
                Image(systemName: "xmark.circle.fill")
                    .foregroundStyle(timer.isRunning ? Color.nextcloudBlue : Color.secondary)
            }
        }
        .bold()
        .padding()
        .background {
            RoundedRectangle(cornerRadius: 20)
                .foregroundStyle(.ultraThickMaterial)
        }
    }
}



class RecipeTimer: ObservableObject {
    var timeTotal: Double
    @Published var duration: DurationComponents
    private var startDate: Date?
    private var pauseDate: Date?
    @Published var timeElapsed: Double = 0
    @Published var isRunning: Bool = false
    @Published var timerExpired: Bool = false
    private var timer: Timer.TimerPublisher?
    private var timerCancellable: Cancellable?
    var audioPlayer: AVAudioPlayer?

    init(duration: DurationComponents) {
        self.duration = duration
        self.timeTotal = duration.toSeconds()
    }
    
    func start() {
        self.isRunning = true
        if startDate == nil {
            startDate = Date()
        } else if let pauseDate = pauseDate {
            // Adjust start date based on the pause duration
            let pauseDuration = Date().timeIntervalSince(pauseDate)
            startDate = startDate?.addingTimeInterval(pauseDuration)
        }
        requestNotificationPermissions()
        scheduleTimerNotification(timeInterval: timeTotal)
        // Prepare audio session
        setupAudioSession()
        prepareAudioPlayer(with: "alarm_sound_0")
        
        self.timer = Timer.publish(every: 1, on: .main, in: .common)
        self.timerCancellable = self.timer?.autoconnect().sink { [weak self] _ in
            DispatchQueue.main.async {
                if let self = self, let startTime = self.startDate {
                    let elapsed = Date().timeIntervalSince(startTime)
                    if elapsed < self.timeTotal {
                        self.timeElapsed = elapsed
                        self.duration.fromSeconds(Int(self.timeTotal - self.timeElapsed))
                    } else {
                        self.timerExpired = true
                        self.timeElapsed = self.timeTotal
                        self.duration.fromSeconds(Int(self.timeTotal - self.timeElapsed))
                        self.pause()
                        
                        self.startAlarm()
                    }
                }
            }
        }
    }
    
    func pause() {
        self.isRunning = false
        pauseDate = Date()
        self.timerCancellable?.cancel()
        self.timerCancellable = nil
        self.timer = nil
    }
    
    func resume() {
        self.isRunning = true
        start()
    }
    
    func cancel() {
        self.isRunning = false
        self.timerCancellable?.cancel()
        self.timerCancellable = nil
        self.timer = nil
        self.timeElapsed = 0
        self.startDate = nil
        self.pauseDate = nil
        self.duration.fromSeconds(Int(timeTotal))
    }
}

extension RecipeTimer {
    func setupAudioSession() {
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
            try AVAudioSession.sharedInstance().setActive(true)
        } catch {
            print("Failed to set audio session category. Error: \(error)")
        }
    }
    
    func prepareAudioPlayer(with soundName: String) {
        if let soundURL = Bundle.main.url(forResource: "alarm_sound_0", withExtension: "mp3") {
            do {
                audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
                audioPlayer?.prepareToPlay()
                audioPlayer?.numberOfLoops = -1 // Loop indefinitely
            } catch {
                print("Error loading sound file: \(error)")
            }
        }
    }
    
    func postNotification() {
        NotificationCenter.default.post(name: Notification.Name("AlarmNotification"), object: nil)
    }

    func startAlarm() {
        audioPlayer?.play()
        postNotification()
    }

    func stopAlarm() {
        audioPlayer?.stop()
        try? AVAudioSession.sharedInstance().setActive(false)
    }
        
    func requestNotificationPermissions() {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            if granted {
                print("Notification permission granted.")
            } else if let error = error {
                print("Notification permission denied because: \(error.localizedDescription).")
            }
        }
    }
    
    func scheduleTimerNotification(timeInterval: TimeInterval) {
        let content = UNMutableNotificationContent()
        content.title = "Timer Finished"
        content.body = "Your timer is up!"
        content.sound = UNNotificationSound.default

        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false)

        let request = UNNotificationRequest(identifier: "timerNotification", content: content, trigger: trigger)

        UNUserNotificationCenter.current().add(request) { error in
            if let error = error {
                print("Error scheduling notification: \(error)")
            }
        }
    }
}
