import UIKit
import PKHUD
import CoreLocation

extension NSError {
    var displayMessage: (title: String, body: String) {
        if let description = self.userInfo[NSLocalizedDescriptionKey] as? String {
            return (title: "Error", body: description)
        } else if let failure = self.userInfo[NSLocalizedFailureErrorKey] as? String, let reason = self.localizedFailureReason {
            if let recovery = self.localizedRecoverySuggestion {
                return (title: failure, body: reason + "\n" + recovery)
            } else {
                return (title: failure, body: reason)
            }
        } else {
            return (title: "Error", body: "")
        }
    }
}

extension CocoaError {
    static func error(_ description: String) -> NSError {
        return error(Code(rawValue: 0), userInfo: [NSLocalizedDescriptionKey: description], url: nil) as NSError
    }
    
    static func error(_ error: String, reason: String, suggestion: String? = nil) -> NSError {
        var info = [
            NSLocalizedFailureErrorKey: error,
            NSLocalizedFailureReasonErrorKey: reason
        ]
        
        if let suggestion = suggestion {
            info[NSLocalizedRecoverySuggestionErrorKey] = suggestion
        }
        
        return self.error(Code(rawValue: 0), userInfo: info, url: nil) as NSError
    }
}

extension UIViewController {
    func show(error: Error, animated: Bool = true, completion: (() -> Void)? = nil) {
        let msg = (error as NSError).displayMessage
        let alert = UIAlertController(title: msg.title, message: msg.body, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
            completion?()
        }))
        self.present(alert, animated: animated)
    }
    
    func showAlert(title: String, message: String) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true)
    }
}

extension HUD {
    static func show(error: Error) {
        let msg = (error as NSError).displayMessage
        self.flash(.labeledError(title: msg.title, subtitle: msg.body), delay: 2.0)
    }
}

extension CLError.Code: CustomStringConvertible {
    public var description: String {
        switch self {
        case .locationUnknown: return "Location unknown"
        case .denied: return "Access denied"
        case .network: return "general, network-related error"
        case .headingFailure: return "heading could not be determined"
        case .regionMonitoringDenied: return "Location region monitoring has been denied"
        case .regionMonitoringSetupDelayed: return "CL could not immediately initialize region monitoring"
        case .regionMonitoringResponseDelayed: return "While events for this fence will be delivered, delivery will not occur immediately"
        case .geocodeFoundNoResult: return "A geocode request yielded no result"
        case .geocodeFoundPartialResult: return "A geocode request yielded a partial result"
        case .geocodeCanceled: return "A geocode request was cancelled"
        case .deferredFailed: return "Deferred mode failed"
        case .deferredNotUpdatingLocation: return "Deferred mode failed because location updates disabled or paused"
        case .deferredAccuracyTooLow: return "Deferred mode not supported for the requested accuracy"
        case .deferredDistanceFiltered: return "Deferred mode does not support distance filters"
        case .deferredCanceled: return "Deferred mode request canceled a previous request"
        case .rangingUnavailable: return "Ranging cannot be performed"
        case .rangingFailure: return "General ranging failure"
        case .promptDeclined: return "Authorization request not presented to user"
        default: return "Unknown location error (\(self.rawValue)"
        }
    }
}
