//
//  LiveTimerView.swift
//  LeCountdown
//
//  Created by Laurent Morvillier on 03/02/2023.
//

import SwiftUI

class LiveStopwatchModel: ObservableObject {
    
    @Published var endDate: Date? = nil
    
    func stop(_ stopwatch: Stopwatch) {
        
        let now = Date()
        self.endDate = now
        
        Conductor.maestro.stopStopwatch(stopwatch)
        
    }
}

struct LiveStopwatchView: View {
    
    @Environment(\.managedObjectContext) private var viewContext
    @EnvironmentObject var conductor: Conductor
    
    @StateObject var model: LiveStopwatchModel = LiveStopwatchModel()
    
    @State var stopwatch: Stopwatch
    var date: Date
    
    var body: some View {
        
        let running = (self.model.endDate == nil)
        
        HStack {
            
            Text(stopwatch.displayName.uppercased()).padding()
            
            Spacer()
            
            if running {
                TimelineView(.periodic(from: self.date, by: 0.01)) { context in
                    Text(self._formattedDuration(date: context.date))
                        .font(.title2)
                        .padding(.trailing)
                        .minimumScaleFactor(0.1)
                }
            } else {
                let duration = self.model.endDate?.timeIntervalSince(self.date) ?? 0.0
                Text(duration.hourMinuteSecondHS)
                    .font(.title2)
                    .padding(.trailing)
                    .minimumScaleFactor(0.1)
            }
            
            if running {
                
                Button {
                    self.model.stop(stopwatch)
                } label: {
                    
                    Image(systemName: "stop.circle.fill")
                        .font(.title)
                        .foregroundColor(.white)
                        .cornerRadius(8.0)
                        .frame(minWidth: 0.0, maxWidth: 60.0, minHeight: 0.0, maxHeight: .infinity)
                }.background(.red)
                
            } else {
                GreenCheckmarkView()
            }
        }.onTapGesture {
            withAnimation {
                self._dismiss()
            }
        }
        .frame(height: 55.0)
        .foregroundColor(.white)
        .monospaced()
        .background(Color(white: 0.2))
        .cornerRadius(16.0)
    }
    
    fileprivate func _dismiss() {
        conductor.removeLiveTimer(id: self.stopwatch.stringId)
    }
    
    fileprivate func _formattedDuration(date: Date) -> String {
        let duration = date.timeIntervalSince(self.date)
        return duration.hourMinuteSecondHS
    }
}

struct LiveCountdownView: View {
    
    @Environment(\.managedObjectContext) private var viewContext
    @EnvironmentObject var conductor: Conductor
    
    @State var countdown: Countdown
    var date: Date
    
    var body: some View {
        HStack {
            Text(self.countdown.displayName.uppercased()).padding()
            Spacer()
            TimelineView(.periodic(from: self.date, by: 0.01)) { context in
                
                if self.date > context.date {
                    
                    HStack {
                        Text(self._formattedDuration(date: context.date))
                            .font(.title2)
                            .minimumScaleFactor(0.1)
                            .padding(.trailing)
                        Button {
                            self._cancelCountdown()
                        } label: {
                            Image(systemName: "xmark.circle.fill")
                                .font(.title)
                                .foregroundColor(.white)
                                .cornerRadius(8.0)
                                .frame(minWidth: 0.0, maxWidth: 60.0, minHeight: 0.0, maxHeight: .infinity)
                        }.background(.red)
                        
                    }
                } else {
                    GreenCheckmarkView()
                }
            }
        }
        .contentShape(Rectangle()) // make the onTap react everywhere
        .onTapGesture {
            withAnimation {
                self._dismiss()
            }
        }
        .frame(height: 55.0)
        .foregroundColor(.white)
        .monospaced()
        .background(Color(white: 0.2))
        .cornerRadius(16.0)
    }
    
    fileprivate func _dismiss() {
        conductor.cancelCountdown(id: self.countdown.stringId)
        conductor.removeLiveTimer(id: self.countdown.stringId)
    }
    
    fileprivate func _formattedDuration(date: Date) -> String {
        let duration = self.date.timeIntervalSince(date)
        return duration.minuteSecond
    }
    
    fileprivate func _cancelCountdown() {
        Conductor.maestro.cancelCountdown(id: self.countdown.stringId)
    }
    
}

struct LiveTimerListView: View {
    
    @Environment(\.managedObjectContext) private var viewContext
    @EnvironmentObject var conductor: Conductor
    
    var body: some View {
        LazyVStack {
            ForEach(conductor.liveTimers) { liveTimer in
                
                if let timer: AbstractTimer = liveTimer.timer(context: self.viewContext) {
                    
                    switch timer {
                    case let cd as Countdown:
                        LiveCountdownView(countdown: cd, date: liveTimer.date)
                    case let sw as Stopwatch:
                        LiveStopwatchView(stopwatch: sw, date: liveTimer.date)
                    default:
                        Text("unmanaged timer: \(timer)")
                    }
                    
                }
                
            }
        }.padding(8.0)
        
    }
    
    
}

struct LiveTimerView_Previews: PreviewProvider {
    
    static var previews: some View {
//        LiveTimerListView().environmentObject(Conductor.maestro)
        
        Group {
            VStack(spacing: 20.0) {
                LiveCountdownView(countdown: Countdown.fake(context: PersistenceController.preview.container.viewContext), date: Date().addingTimeInterval(3600.0))
                    .environmentObject(Conductor.maestro)
                LiveStopwatchView(stopwatch: Stopwatch.fake(context: PersistenceController.preview.container.viewContext), date: Date())
                    .environmentObject(Conductor.maestro)
            }
        }.padding()
    }
    
}
