import AVFoundation
import Cocoa
import UserNotifications

class MVTimerController: NSWindowController {
    private var mainView: MVMainView!
    private var clockView: MVClockView!
    
    private var audioPlayer: AVAudioPlayer? // player must be kept in memory
    private var soundURL = Bundle.main.url(forResource: "alert-sound", withExtension: "caf")
    
    convenience init() {
        let mainView = MVMainView(frame: NSRect.zero)
        
        let window = MVWindow(mainView: mainView)
        
        self.init(window: window)
        
        self.mainView = mainView
        self.mainView.controller = self
        self.clockView = MVClockView()
        self.clockView.target = self
        self.clockView.action = #selector(handleClockTimer)
        self.mainView.addSubview(clockView)
        
        self.setAudioPlayer()
        
        self.windowFrameAutosaveName = "TimerWindowAutosaveFrame"
        
        window.makeKeyAndOrderFront(self)
    }
    
    convenience init(closeToWindow: NSWindow?) {
        self.init()
        
        if closeToWindow != nil {
            var point = closeToWindow!.frame.origin
            point.x += CGFloat(Int(arc4random_uniform(UInt32(80))) - 40)
            point.y += CGFloat(Int(arc4random_uniform(UInt32(80))) - 40)
            self.window?.setFrameOrigin(point)
        }
    }
    
    deinit {
        self.clockView.target = nil
        self.clockView.stop()
    }
    
    func showInDock(_ state: Bool) {
        self.clockView.inDock = state
        self.mainView.menuItem?.state = state ? .on : .off
    }
    
    func windowVisibilityChanged(_ visible: Bool) {
        self.clockView.windowIsVisible = visible
    }
    
    func playAlarmSound() {
        // we can always play because the player has been initialised in the
        // constructor and when changing the sound
        self.audioPlayer?.play()
    }
    
    @objc func handleClockTimer(_ clockView: MVClockView) {
        let notificationContent = UNMutableNotificationContent()
        
        var titleText = ""
        var bodyText = ""
        if clockView.state == .Activity {
            titleText = "It's time for a break! 🕙"
            bodyText = "You have earned yourself a break"
        } else {
            titleText = "Break's over ⏰"
            bodyText = "Time to get back to work"
        }
        notificationContent.title = titleText
        notificationContent.body = bodyText
        
        let notification = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil)
        
        // Schedule the request with the system.
        let notificationCenter = UNUserNotificationCenter.current()
        notificationCenter.add(notification) { (error) in
            if error != nil { // should only occure if permissions are inadequate or system error (but we ignore that posibility)
                let alert = NSAlert()
                alert.messageText = titleText
                alert.informativeText = bodyText + "\n\nIf you wish to receive notifications instead of pop-up alerts in the future, please adjust the notification permissions for this app in the settings!"
                alert.alertStyle = .informational
                alert.addButton(withTitle: "Ok")
                alert.runModal()
            }
        }
        
        // makes it so it "jumps" in the dock
        NSApplication.shared.requestUserAttention(.criticalRequest)
        
        self.playAlarmSound()
        
        // if an activity finished, set precalculated break time
        if clockView.state == .Activity {
            clockView.setCalculatedBreakTime()
            clockView.state = .BeforeBreak
            clockView.previousState = .BeforeBreak
        } else {
            clockView.state = .NotStarted
            clockView.previousState = .NotStarted
        }
        clockView.inputSeconds = false
    }
    
    override func keyUp(with theEvent: NSEvent) {
        self.clockView.keyUp(with: theEvent)
    }
    
    override func keyDown(with event: NSEvent) {
    }
    
    private func setAudioPlayer() {
        do {
            try self.audioPlayer = AVAudioPlayer(contentsOf: self.soundURL!, fileTypeHint: "caf")
        } catch {
            let alert = NSAlert()
            alert.messageText = "Failed to initialise audio player"
            alert.informativeText = "The program will exit now"
            alert.alertStyle = .critical
            alert.addButton(withTitle: "Ok")
            alert.runModal()
            
            exit(1)
        }
    }
    
    func pickSound(_ index: Int) {
        let sound: String?
        
        switch index {
        case -1:
            sound = nil
        case 0:
            sound = "alert-sound"
            
        case 1:
            sound = "alert-sound-2"
            
        case 2:
            sound = "alert-sound-3"
            
        default:
            sound = "alert-sound"
        }
        
        if sound != nil {
            self.soundURL = Bundle.main.url(forResource: sound, withExtension: "caf")
            
            self.setAudioPlayer()
            
            // 'preview'
            self.playAlarmSound()
        } else {
            self.soundURL = nil
        }
    }
}
