
import Foundation
import UIKit

extension Collection {
    func get(at index: Index) -> Iterator.Element? {
        return self.indices.contains(index) ? self[index] : nil
    }
}

extension UIView {
    
    @IBInspectable var iscircleCorner: Bool {
        get {
            return min(bounds.size.height, bounds.size.width) / 2 == cornerRadiusV
        }
        set {
            cornerRadiusV = newValue ? min(bounds.size.height, bounds.size.width) / 2 : cornerRadiusV
        }
    }
    
    @IBInspectable var cornerRadiusV: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
            layer.masksToBounds = newValue > 0
        }
    }
    
    @IBInspectable var borderWidthV: CGFloat {
        get {
            return layer.borderWidth
        }
        set {
            layer.borderWidth = newValue
        }
    }
    
    @IBInspectable var borderColorV: UIColor? {
        get {
            return UIColor(cgColor: layer.borderColor!)
        }
        set {
            layer.borderColor = newValue?.cgColor
        }
    }
    
    @IBInspectable var shadowRadius: CGFloat {
        get {
            return layer.shadowRadius
        }
        set {
            layer.shadowRadius = newValue
        }
    }
}

enum UserDefaultsKeys : String {
    case isLoggedIn
    case userID
}

extension UserDefaults {
    
    func setLoggedIn(value: Bool) {
        set(value, forKey: UserDefaultsKeys.isLoggedIn.rawValue)
        //synchronize()
    }
    
    func isLoggedIn() -> Bool {
        return bool(forKey: UserDefaultsKeys.isLoggedIn.rawValue)
    }
    
    func setUserSession(value: [String: Any], ForKey: String) {
        set(value, forKey: ForKey)
        //synchronize()
    }
    
    func getUserSessions(Key: String) -> [String: Any] {
        return object(forKey: Key) as? [String: Any] ?? [:]
    }
    
    func setSwitchAccountData(value: [[String: Any]], ForKey: String) {
        set(value, forKey: ForKey)
        //synchronize()
    }
    
    func getSwitchAccountData(Key: String) -> [[String: Any]] {
        return object(forKey: Key) as? [[String: Any]] ?? []
    }
    
    func setDownloadOption(value: [String], ForKey: String) {
        set(value, forKey: ForKey)
        //synchronize()
    }
    
    func getDownloadOption(Key: String) -> [String] {
        return object(forKey: Key) as? [String] ?? []
    }
    
    func setChatColorHex(value: String, ForKey: String) {
        set(value, forKey: ForKey)
        //synchronize()
    }
    
    func getChatColorHex(Key: String) -> String {
        return object(forKey: Key) as? String ?? ""
    }
    
    func setCallLogs(value: [Data], ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getCallLogs(Key: String) -> [Data] {
        return object(forKey: Key) as? [Data] ?? []
    }
    
    func setCallNotification(value: [[String: Any]], ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getCallNotification(Key: String) -> [[String: Any]] {
        return object(forKey: Key) as? [[String: Any]] ?? []
    }
    
    func setNotification(value: Bool, ForKey: String) {
        set(value, forKey: ForKey)
    }
    
    func getNotification(Key: String) -> Bool {
        return object(forKey: Key) as? Bool ?? true
    }
    
    func setLanguage(value: String, ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getLanguage(Key:String) ->  String{
        return object(forKey: Key) as? String ?? ""
    }
    
    func setDeviceId(value: String, ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getDeviceId(Key: String) -> String {
        return object(forKey: Key) as? String ?? ""
    }
    
    func setDarkMode(value: Bool, ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getDarkMode(Key:String) ->  Bool {
        return ((object(forKey: Key) as? Bool) ?? false)!
    }
    
    func setSystemTheme(value: Bool, ForKey: String) {
        set(value, forKey: ForKey)
        // synchronize()
    }
    
    func getSystemTheme(Key: String) -> Bool {
        return object(forKey: Key) as? Bool ?? false
    }
    
    func setFingerprintLock(value: Bool, ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getFingerprintLock(Key: String) ->  Bool {
        return (object(forKey: Key) as? Bool) ?? false
    }
    
    func setNotificationStatus(value: Bool, ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getNotificationStatus(Key: String) ->  Bool {
        return object(forKey: Key) as? Bool ?? false
    }
    
    func setConversationTone(value: Bool, ForKey: String) {
        set(value, forKey: ForKey)
        synchronize()
    }
    
    func getConversationTone(Key: String) ->  Bool {
        return object(forKey: Key) as? Bool ?? false
    }
    
    func clearUserDefaults() {
        if let bundleID = Bundle.main.bundleIdentifier {
            UserDefaults.standard.removePersistentDomain(forName: bundleID)
        }
    }
    
    func removeValuefromUserdefault(Key: String) {
        removeObject(forKey: Key)
    }
}

extension String {
    var isBlank: Bool {
        return self.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
    }
    var isEmail: Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,20}"
        let emailTest  = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailTest.evaluate(with: self)
    }
    
    var htmlToAttributedString: NSAttributedString? {
        guard let data = data(using: .utf8) else { return nil }
        do {
            return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil)
        } catch {
            return nil
        }
    }
    var htmlToString: String {
        return htmlToAttributedString?.string ?? ""
    }
}
extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }
    
    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}
extension UINavigationController {
    
    func popToViewController(ofClass: AnyClass, animated: Bool = true) {
        if let vc = viewControllers.filter({$0.isKind(of: ofClass)}).last {
            popToViewController(vc, animated: animated)
        }
    }
    
    func popViewControllers(viewsToPop: Int, animated: Bool = true) {
        if viewControllers.count > viewsToPop {
            let vc = viewControllers[viewControllers.count - viewsToPop - 1]
            popToViewController(vc, animated: animated)
        }
    }
}

extension String {
    /// Converts HTML string to a `NSAttributedString`
    
    var htmlAttributedString: String? {
        return try? NSAttributedString(data: Data(utf8), options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil).string
    }
}

extension Data {
    private static let mimeTypeSignatures: [UInt8 : String] = [
        0xFF : "image/jpeg",
        0x89 : "image/png",
        0x47 : "image/gif",
        0x49 : "image/tiff",
        0x4D : "image/tiff",
        0x25 : "application/pdf",
        0xD0 : "application/vnd",
        0x46 : "text/plain",
    ]
    
    var mimeType: String {
        var c: UInt8 = 0
        copyBytes(to: &c, count: 1)
        return Data.mimeTypeSignatures[c] ?? "application/octet-stream"
    }
}

extension UIColor {
    func toHexString() -> String {
        var r:CGFloat = 0
        var g:CGFloat = 0
        var b:CGFloat = 0
        var a:CGFloat = 0
        
        getRed(&r, green: &g, blue: &b, alpha: &a)
        
        let rgb:Int = (Int)(r*255)<<16 | (Int)(g*255)<<8 | (Int)(b*255)<<0
        
        return String(format:"#%06x", rgb)
    }
}

extension UITextView {
    
    private class PlaceholderLabel: UILabel { }
    
    private var placeholderLabel: PlaceholderLabel {
        if let label = subviews.compactMap( { $0 as? PlaceholderLabel }).first {
            return label
        } else {
            let label = PlaceholderLabel(frame: .zero)
            label.font = font
            addSubview(label)
            return label
        }
    }
    
    @IBInspectable
    var placeholder: String {
        get {
            return subviews.compactMap( { $0 as? PlaceholderLabel }).first?.text ?? ""
        }
        set {
            let placeholderLabel = self.placeholderLabel
            placeholderLabel.text = newValue
            placeholderLabel.numberOfLines = 0
            let width = frame.width - textContainer.lineFragmentPadding * 2
            let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
            placeholderLabel.frame.size.height = size.height
            placeholderLabel.frame.size.width = width
            placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)
            
            textStorage.delegate = self
        }
    }
    
    func addPlaceholder(_ placeholder: String, with color: UIColor = .lightGray) {
        let placeholderLabel = self.placeholderLabel
        placeholderLabel.font = self.font
        placeholderLabel.numberOfLines = 0
        placeholderLabel.text = placeholder
        placeholderLabel.textColor = color
        let width = frame.width - textContainer.lineFragmentPadding * 2
        let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
        placeholderLabel.frame.size.height = size.height
        placeholderLabel.frame.size.width = width
        placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)
        textStorage.delegate = self
    }
    
    func addPlaceholder(_ placeholder: String, alignment: NSTextAlignment = .natural) {
        let placeholderLabel = self.placeholderLabel
        placeholderLabel.textAlignment = alignment
        placeholderLabel.textColor = self.textColor
        placeholderLabel.font = self.font
        placeholderLabel.numberOfLines = 0
        placeholderLabel.text = placeholder
        let width = frame.width - textContainer.lineFragmentPadding * 2
        let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
        placeholderLabel.frame.size.height = size.height
        placeholderLabel.frame.size.width = width
        placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)
        textStorage.delegate = self
    }
    
}

extension UITextView: NSTextStorageDelegate {
    
    public func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {
        if editedMask.contains(.editedCharacters) {
            placeholderLabel.isHidden = !text.isEmpty
        }
    }
    
}
extension Double {
    func getDateStringFromUTC() -> String {
        let date = Date(timeIntervalSince1970: self)
        
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US")
        dateFormatter.dateStyle = .medium
        
        return dateFormatter.string(from: date)
    }
}

extension UIApplication {
    /// Checks if view hierarchy of application contains `UIRemoteKeyboardWindow` if it does, keyboard is presented
    var isKeyboardPresented: Bool {
        if let keyboardWindowClass = NSClassFromString("UIRemoteKeyboardWindow"),
           self.windows.contains(where: { $0.isKind(of: keyboardWindowClass) }) {
            return true
        } else {
            return false
        }
    }
}

extension UITextField {
    
    @IBInspectable var placeHolderColor: UIColor? {
        get {
            return self.placeHolderColor
        } set {
            self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSAttributedString.Key.foregroundColor: newValue!])
        }
    }
    
}

extension UITableView {
    
    func indicatorView() -> UIActivityIndicatorView{
        var activityIndicatorView = UIActivityIndicatorView()
        if self.tableFooterView == nil {
            let indicatorFrame = CGRect(x: 0, y: 0, width: self.bounds.width, height: 80)
            activityIndicatorView = UIActivityIndicatorView(frame: indicatorFrame)
            activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
            
            if #available(iOS 13.0, *) {
                activityIndicatorView.style = .large
            } else {
                // Fallback on earlier versions
                activityIndicatorView.style = .whiteLarge
            }
            
            activityIndicatorView.color = .systemPink
            activityIndicatorView.hidesWhenStopped = true
            
            self.tableFooterView = activityIndicatorView
            return activityIndicatorView
        }
        else {
            return activityIndicatorView
        }
    }
    
    func addLoading(_ indexPath:IndexPath, closure: @escaping (() -> Void)){
        indicatorView().startAnimating()
        if let lastVisibleIndexPath = self.indexPathsForVisibleRows?.last {
            if indexPath == lastVisibleIndexPath && indexPath.row == self.numberOfRows(inSection: 0) - 1 {
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    closure()
                }
            }
        }
    }
    
    func stopLoading() {
        if self.tableFooterView != nil {
            self.indicatorView().stopAnimating()
            self.tableFooterView = nil
        }
        else {
            self.tableFooterView = nil
        }
    }
}
