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

import SwiftUI
import CoreData
import Combine
import _AppIntents_SwiftUI

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

class TimerSpot : Identifiable, Equatable {
    
    var id: Int16 { return self.order }
    
    var order: Int16
    var timer: AbstractTimer?
    
    init(order: Int16, timer: AbstractTimer? = nil) {
        self.order = order
        self.timer = timer
    }
    
    func setOrder(order: Int16) {
        self.order = order
        self.timer?.order = order
    }
    
    static func == (lhs: TimerSpot, rhs: TimerSpot) -> Bool {
        return lhs.order == rhs.order && lhs.timer?.stringId == rhs.timer?.stringId
    }

}

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>
    
    @State private var isEditing: Bool = false
    
    @State private var tipsShown: Bool = false
    
    @State private var siriTipShown: Bool = false
    
    fileprivate let itemSpacing: CGFloat = 10.0

    var body: some View {
        
        let columns: [GridItem] = self._columns()
        let timers: [AbstractTimer] = Array(self.timers)
        
        Group {
            if timers.count > 0 {
                
                GeometryReader { reader in
                    let width: CGFloat = reader.size.width / CGFloat(columns.count) - 15.0
                    
                    VStack {
                        
                        ScrollView {
                            
                            LazyVGrid(
                                columns: columns,
                                spacing: itemSpacing
                            ) {
                                
                                ReorderableForEach(items: timers) { timer in
                                    
                                    DialView(timer: timer, isEditingBinding: self.$isEditing, frameSize: width, handler: { id in
                                        self._handleSiriTips(timerId: id)
                                    })
                                    .environment(\.managedObjectContext, viewContext)
                                    .environmentObject(Conductor.maestro)
                                    .environmentObject(boringContext)
                                } moveAction: { from, to in
                                    self._reorder(from: from, to: to)
                                }
                                
                            }
                        }.padding(.horizontal, itemSpacing)
                        
                        //                if !self.tipsShown, let tip = Preferences.tipToShow {
                        //                    TipView(tip: tip) {
                        //                        self._hideTip(tip)
                        //                    }.padding()
                        //                }
                        
                        Spacer()
                        
                        SiriTipView(intent: StartTimerIntent(), isVisible: self.$siriTipShown)
                            .siriTipViewStyle(SiriTipViewStyle.dark).padding()
                        
                        if !conductor.liveTimers.isEmpty {
                            
                            HStack(alignment: .center) {
                                VolumeView().padding(12.0)
                            }.frame(width: 300.0, height: 40.0)
                                .background(Color(white: 0.9))
                                .cornerRadius(16.0)
                            
                            LiveTimerListView()
                                .environment(\.managedObjectContext, viewContext)
                                .environmentObject(conductor)
                                .foregroundColor(.white)
                                .background(Color(white: 0.1))
                                .cornerRadius(32.0, corners: [.topRight, .topLeft])
                        }
                    }
                }
            } else {
                Text("You'll find your timers here. Start by creating them on the left screen")
            }
        }
        .navigationTitle("Home")
        .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)
        })
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button {
                    withAnimation {
                        self.isEditing.toggle()
                    }
                } label: {
                    Text(self.isEditing ? "Done" : "Edit")
                }
            }
        }
        .onAppear {
            self._askPermissions()
        }
        .onOpenURL { url in
            self._performActionIfPossible(url: url)
        }
        
    }
    
    fileprivate func _columnCount() -> Int {
        #if os(iOS)
        if UIDevice.isPhoneIdiom {
            return 2
        } else {
            return 3
        }
        #else
        return 3
        #endif
    }
    
    fileprivate func _columns() -> [GridItem] {
        return (0..<self._columnCount()).map { _ in GridItem(spacing: 10.0) }
    }
        
    // MARK: - Business

    fileprivate func _hideTip(_ tip: Tip) {
        Preferences.lastShownTip = tip.rawValue
        self.tipsShown = true
    }
    
    fileprivate func _reorder(from: IndexSet, to: Int) {
        var timers: [AbstractTimer] = Array(self.timers)
        timers.move(fromOffsets: from, toOffset: to)
        for (i, countdown) in timers.enumerated() {
            countdown.order = Int16(i)
        }
        do {
            try viewContext.save()
        } catch {
            Logger.error(error)
            self.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 _handleSiriTips(timerId: String) {
        if !Preferences.timerSiriTips.contains(timerId) {
            self.siriTipShown = true
            Preferences.timerSiriTips.insert(timerId)
        }
    }
    
    fileprivate func _performActionIfPossible(url: URL) {
        
        // hide new window if launching a timer
        self.boringContext.isShowingNewData = false
        
        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 TimerRouterError.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)

    }
}
