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

import SwiftUI
import CoreData
import WidgetKit

struct NewCountdownView : View {
    
    @Environment(\.managedObjectContext) private var viewContext
    
    @Binding var isPresented: Bool

    var body: some View {
        CountdownEditView(isPresented: $isPresented)
            .environment(\.managedObjectContext, viewContext)
            .navigationTitle("New countdown")
    }
    
}

struct CountdownEditView : View {
    
    @Environment(\.managedObjectContext) private var viewContext
    @Environment(\.dismiss) private var dismiss
    
    var countdown: Countdown? = nil

    @Binding var isPresented: Bool
    
    @State var secondsString: String = ""
    @State var minutesString: String = ""
    @State var nameString: String = ""

    @State var sound: Sound = .trainhorn
    @State var soundRepeats: Bool = true
    @State var image: CoolPic = .pic1

    @State var deleteConfirmationShown: Bool = false
    @State var activityNameConfirmationShown: Bool = false
    @State fileprivate var _rename: Bool? = nil

    @State var errorShown: Bool = false
    @State var error: Error? = nil
    
    @FocusState private var textFieldIsFocused: Bool

    @FetchRequest(sortDescriptors: [])
    private var countdowns: FetchedResults<Countdown>
    
    @State var _isAdding: Bool = false
    
    @Environment(\.isPresented) var envIsPresented
    
    var body: some View {
        NavigationStack {
            Rectangle()
                .frame(width: 0.0, height: 0.0)
                .onChange(of: envIsPresented) { newValue in
                    if !newValue && !self._isAdding {
                        self._save()
                    }
                }
            CountdownFormView(
                secondsBinding: $secondsString,
                minutesBinding: $minutesString,
                nameBinding: $nameString,
                imageBinding: $image,
                soundBinding: $sound,
                repeatsBinding: $soundRepeats,
                textFieldIsFocused: $textFieldIsFocused)
            .onAppear {
                self._onAppear()
            }
            .confirmationDialog("", isPresented: $deleteConfirmationShown, actions: {
                Button("Yes", role: .destructive) {
                    withAnimation {
                        self._delete()
                    }
                }.keyboardShortcut(.defaultAction)
                Button("No", role: .cancel) {}
            }, message: {
                Text("Do you really want to delete?")
            })
            .confirmationDialog("", isPresented: $activityNameConfirmationShown, actions: {
                Button("Rename") {
                    self._rename = true
                    self._save()
                }
                Button("New activity") {
                    self._rename = false
                    self._save()
                }
            }, message: {
                Text("Do you wish to rename or create a new activity")
            })

            .alert("", isPresented: $errorShown, actions: { }, message: {
                Text(error?.localizedDescription ?? "error")
            })
            .toolbar {
                if self._isAdding {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button("Cancel") {
                            self._cancel()
                        }
                    }
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("Save") {
                            self._save()
                        }
                    }
                } else {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button {
                            self.deleteConfirmationShown = true
                        } label: {
                            Image(systemName: "trash")
                        }
                    }
                }
                ToolbarItemGroup(placement: .keyboard) {
                    Button {
                        textFieldIsFocused = false
                    } label: {
                        Image(systemName: "checkmark")
                    }
                }
            }
            .navigationTitle("Edit countdown")
        }
        
    }
    
    fileprivate func _onAppear() {
        
        self._isAdding = (self.countdown == nil)
        
        if let countdown {
            
            let minutes = Int(countdown.duration / 60.0)
            let seconds = countdown.duration - Double(minutes * 60)
            
            if minutes > 0 {
                self.minutesString = self._numberFormatter.string(from: NSNumber(value: minutes)) ?? ""
            }

            if seconds > 0 {
                self.secondsString = self._numberFormatter.string(from: NSNumber(value: seconds)) ?? ""
            }
            
            if let name = countdown.activity?.name, !name.isEmpty {
                self.nameString = name
            }
            
            if let sound = Sound(rawValue: Int(countdown.sound)) {
                self.sound = sound
            }
            self.soundRepeats = countdown.repeats
            
            if let image = countdown.image, let coolpic = CoolPic(rawValue: image) {
                self.image = coolpic
            }
        }
        
    }
    
    fileprivate let _numberFormatter = NumberFormatter()
    
    fileprivate var _seconds: Double {
        return self._numberFormatter.number(from: self.secondsString)?.doubleValue ?? 0.0
    }
    
    fileprivate var _minutes: Double {
        return self._numberFormatter.number(from: self.minutesString)?.doubleValue ?? 0.0
    }
    
    fileprivate func _cancel() {
        viewContext.rollback()
        self.isPresented = false
    }
    
    fileprivate func _save() {
        
        let cd: Countdown
        if let countdown {
            cd = countdown
        } else {
            cd = Countdown(context: viewContext)
        }
        
        cd.duration = self._minutes * 60.0 + self._seconds
        if self._isAdding {
            let max = self.countdowns.map { $0.order }.max() ?? 0
            cd.order = max + 1
        }
        
        cd.image = self.image.rawValue
        cd.sound = Int16(self.sound.rawValue)
        cd.repeats = self.soundRepeats
        
        if !self.nameString.isEmpty {
            
            let trimmed = self.nameString.trimmingCharacters(in: .whitespacesAndNewlines)
            
            if let activity = cd.activity, let currentActivityName = activity.name, trimmed != currentActivityName {
                
                switch self._rename {
                case .none:
                    self.activityNameConfirmationShown = true
                    return
                case .some(let rename):
                    if rename {
                        activity.name = trimmed
                    } else {
                        cd.activity = CoreDataRequests.getOrCreateActivity(name: trimmed)
                    }
                }
            } else {
                cd.activity = CoreDataRequests.getOrCreateActivity(name: trimmed)
            }
            
        }
        
        self._saveContext()
        
        WidgetCenter.shared.reloadAllTimelines() // refreshes the visual of existing widgets
        
        self._popOrDismiss()
    }
    
    fileprivate func _popOrDismiss() {
        if self._isAdding {
            self.isPresented = false
        } else {
            dismiss()
        }
    }
    
    fileprivate func _delete() {
        
        guard let countdown else {
            return
        }
        
        viewContext.delete(countdown)
        self._saveContext()

        WidgetCenter.shared.reloadAllTimelines() // refreshes the visual of existing widgets

        self._popOrDismiss()
    }
    
    fileprivate func _saveContext() {
        do {
            try viewContext.save()
        } catch {
            self.errorShown = true
            self.error = error
        }
    }
    
}

struct NewCountdownView_Previews: PreviewProvider {
    static var previews: some View {
        NewCountdownView(isPresented: .constant(true))
            .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}
