//
//  ContentView.swift
//  LeCountdown
//
//  Created by Laurent Morvillier on 20/01/2023.
//

import SwiftUI
import CoreData

class BoringContext : ObservableObject {
    
    @Published var isShowingNewData = false
    @Published var error: Error?
    @Published var showDefaultAlert: Bool = false
    @Published var showPermissionAlert: Bool = false
    
}

struct ContentView<T : AbstractTimer>: View {

    @StateObject var boringContext: BoringContext = BoringContext()
    @EnvironmentObject var conductor: Conductor

    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \T.order, ascending: true)],
        animation: .default)
    private var timers: FetchedResults<T>
    
    fileprivate let itemSpacing: CGFloat = 10.0

    private let columns: [GridItem] = [
        GridItem(spacing: 10.0),
        GridItem(spacing: 10.0),
    ]
    
    var timersArray: [T] {
        return Array(timers)
    }
    
    var body: some View {
        
        NavigationStack {
            GeometryReader { reader in
                let width: CGFloat = reader.size.width / 2 - 10.0
                
                VStack {
                    
                    ScrollView {
                        
                        LazyVGrid(
                            columns: columns,
                            spacing: itemSpacing
                        ) {
                            
                            ReorderableForEach(items: timersArray) { timer in
                                
                                DialView(timer: timer, frameSize: width)       .environment(\.managedObjectContext, viewContext)
                                    .environmentObject(Conductor.maestro)
                                    .environmentObject(boringContext)

                            } moveAction: { from, to in
                                self._reorder(from: from, to: to)
                            }
                        }
                    }.padding(.horizontal, itemSpacing)
                    
                    if !conductor.liveTimers.isEmpty {
                        LiveTimerListView()  .environment(\.managedObjectContext, viewContext)
                            .environmentObject(conductor)
                            .background(Color(white: 0.9))
                            .cornerRadius(16.0, corners: [.topRight, .topLeft])
                    }
                }
            }
                .navigationTitle("\(String(describing: T.self))")
            .alert(boringContext.error?.localizedDescription ?? "missing error", isPresented: $boringContext.showDefaultAlert) {
                Button("OK", role: .cancel) { }
            }
            .alert("You need to accept notifications, please check your settings", isPresented: $boringContext.showPermissionAlert) {
                PermissionAlertView()
            }
            .sheet(isPresented: $boringContext.isShowingNewData, content: {
                self._newView(isPresented: $boringContext.isShowingNewData)
                    .environment(\.managedObjectContext, viewContext)
            })
//            .sheet(isPresented: $boringContext.isShowingNewData, content: {
//                NewStopwatchView(isPresented: $boringContext.isShowingNewData)       .environment(\.managedObjectContext, viewContext)
//            })
//            .sheet(isPresented: $boringContext.isShowingNewData, content: {
//                NewAlarmView(isPresented: $boringContext.isShowingNewData)       .environment(\.managedObjectContext, viewContext)
//            })
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        self.boringContext.isShowingNewData = true
                    } label: {
                        HStack {
                            Image(systemName: "plus")
                        }
                    }
                }
                ToolbarItem(placement: .navigationBarLeading) {
                    EditButton()
                }
            }
            .onAppear {
                self._askPermissions()
            }
            .onOpenURL { url in
                self._performActionIfPossible(url: url)
            }
        }
        
    }
    
    @ViewBuilder
    fileprivate func _newView(isPresented: Binding<Bool>) -> some View {
        switch T.self {
        case is Countdown.Type:
            NewCountdownView(isPresented: isPresented)
        case is Alarm.Type:
            NewAlarmView(isPresented: isPresented)
        case is Stopwatch.Type:
            NewStopwatchView(isPresented: isPresented)
        default:
            Text("missing new view")
        }
        
    }

    fileprivate func _reorder(from: IndexSet, to: Int) {
        var timers: [AbstractTimer] = self.timersArray
        timers.move(fromOffsets: from, toOffset: to)
        for (i, countdown) in timers.enumerated() {
            countdown.order = Int16(i)
        }
        do {
            try viewContext.save()
        } catch {
            boringContext.error = error
        }
    }
    
    fileprivate func _askPermissions() {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { success, error in
            print("requestAuthorization > success = \(success), error = \(String(describing: error))")
        }
    }
    
    fileprivate func _performActionIfPossible(url: URL) {
        
        print("_performActionIfPossible")
        
        let urlString = url.absoluteString
        if let timer = viewContext.object(stringId: urlString) as? AbstractTimer {
            
            if timer is T {
                print("performAction")

                TimerRouter.performAction(timer: timer) { result in
                    switch result {
                    case .success:
                        break
                    case .failure(let failure):
                        switch failure {
                        case TimerError.notificationAuthorizationMissing:
                            self.boringContext.showPermissionAlert = true
                        default:
                            self.boringContext.error = failure
                            self.boringContext.showDefaultAlert = true
                        }
                    }
                }

            }
            
//            print("Start countdown: \(countdown.name ?? ""), \(countdown.duration)")
//            self._launchCountdown(countdown)
        } else {
            print("timer not found with id = \(urlString)")
        }
        
    }
    
}

struct MainToolbarView: View {
    
    var isShowingNewData: Binding<Bool>
    
    var body: some View {
        Button {
            self.isShowingNewData.wrappedValue = true
        } label: {
            HStack {
                Image(systemName: "timer")
                Text("countdown")
            }
        }
        Button {
            self.isShowingNewData.wrappedValue = true
        } label: {
            HStack {
                Image(systemName: "stopwatch")
                Text("stopwatch")
            }
        }
        Button {
            self.isShowingNewData.wrappedValue = true
        } label: {
            HStack {
                Image(systemName: "alarm")
                Text("alarm")
            }
        }

    }
}

fileprivate extension Countdown {
    
    var endDate: Date? {
        return Conductor.maestro.currentCountdowns[self.stringId]?.end
    }
    
    var isLive: Bool {
        return endDate != nil
    }
    
    var colorForStatus: Color {
        if isLive {
            return Color(red: 0.9, green: 1.0, blue: 0.95)
        } else {
            return Color(red: 0.9, green: 0.95, blue: 1.0)
        }
    }
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView<Countdown>().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)                    .environmentObject(Conductor.maestro)

    }
}
