//
//  StringExtension.swift
//  ScanQR
//
//  Created by Dev. Mohmd on 7/14/20.
//  Copyright © 2020 Dev. Mohmd. All rights reserved.
//

import Foundation
import UIKit

extension String {
    
    func timeStampStringToTime() -> String {
        let timestampString = self
        let unixTimestamp = TimeInterval(timestampString) ?? 0
        let date = Date(timeIntervalSince1970: unixTimestamp)
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "hh:mm a"
        let timeString = dateFormatter.string(from: date)
        return timeString
    }
    
    public var isNotEmpty: Bool {
        return !isEmpty
    }
    
    public var isNumeric : Bool {
        get {
            NumberFormatter().number(from: self) != nil
        }
    }
    
    public func localize(_ className: Self? = nil) -> String {
        let tableName = className == nil ? "Localizable" : className
        return NSLocalizedString(self, tableName: tableName, bundle: .main, value: self, comment: self)
    }
    
    public func removeWhiteSpacing() -> String {
        return self.replacingOccurrences(of: " ", with: "")
    }
    
    public func chunkFormatted(withChunkSize chunkSize: Int = 4, withSeparator separator: Character = "-") -> String {
        return self.filter { $0 != separator }.chunk(n: chunkSize).map{ String($0) }.joined(separator: String(separator))
    }
    
    public func base64Encoded() -> String? {
        return data(using: .utf8)?.base64EncodedString()
    }
    
    public func base64Decoded() -> String? {
        guard let data = Data(base64Encoded: self) else { return nil }
        return String(data: data, encoding: .utf8)
    }
    
    public func hexStringToUIColor() -> UIColor {
        var cString: String = self.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
        if (cString.hasPrefix("#")) {
            cString.remove(at: cString.startIndex)
        }
        if ((cString.count) != 6) {
            return UIColor.gray
        }
        var rgbValue:UInt64 = 0
        Scanner(string: cString).scanHexInt64(&rgbValue)
        return UIColor(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: CGFloat(1)
        )
    }
    
    public func formatToDate(_ format: String) -> Date? {
        return self.convertFormatStringToDate(format)
    }
    
    mutating func insert(separator: String, every n: Int) {
        self = inserting(separator: separator, every: n)
    }
    
    func inserting(separator: String, every n: Int) -> String {
        var result: String = ""
        let characters = Array(self)
        stride(from: 0, to: count, by: n).forEach {
            result += String(characters[$0..<min($0+n, count)])
            if $0+n < count {
                result += separator
            }
        }
        return result
    }
    
    private static let formatter = NumberFormatter()
    
    public func clippingCharacters(in characterSet: CharacterSet) -> String {
        components(separatedBy: characterSet).joined()
    }
    
    public func convertedDigitsToLocale(_ locale: Locale = .current) -> String {
        let digits = Set(clippingCharacters(in: CharacterSet.decimalDigits.inverted))
        guard !digits.isEmpty else { return self }
        
        Self.formatter.locale = locale
        let maps: [(original: String, converted: String)] = digits.map {
            let original = String($0)
            guard let digit = Self.formatter.number(from: String($0)) else {
                assertionFailure("Can not convert to number from: \(original)")
                return (original, original)
            }
            guard let localized = Self.formatter.string(from: digit) else {
                assertionFailure("Can not convert to string from: \(digit)")
                return (original, original)
            }
            return (original, localized)
        }
        
        var converted = self
        for map in maps { converted = converted.replacingOccurrences(of: map.original, with: map.converted) }
        return converted
    }
    
    public func correctUrlString() -> String {
        return self.replacingOccurrences(of: "\\", with: "/")
    }
    
    public func isValidEmail() -> Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
        let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailTest.evaluate(with: self)
    }
    
    internal func getImageFromURLString(completion: @escaping (Bool, UIImage?) -> Void) {
        DispatchQueue.global(qos: .background).async {
            do {
                guard let url = URL(string: self.correctUrlString()) else {
                    completion(false, nil)
                    return
                }
                let data = try Data(contentsOf: url)
                DispatchQueue.main.async {
                    guard let image = UIImage(data: data) else {
                        completion(false, nil)
                        return
                    }
                    completion(true, image)
                }
            } catch {
                completion(false, nil)
            }
        }
    }
    
    public func convertBase64StringToImage() -> UIImage {
        let imageData = Data(base64Encoded: self, options: .init(rawValue: 0))
        let image = UIImage(data: imageData!)
        return image!
    }
    
    public func convertFormatStringToDate(_ format: String) -> Date? {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier:"en_US_POSIX")
        dateFormatter.timeZone = .GMT
        dateFormatter.dateFormat = format
        let convertedDate = dateFormatter.date(from: self)
        return convertedDate
    }
    
    func emojiToImage(size: CGFloat) -> UIImage {
        
        let outputImageSize = CGSize.init(width: size, height: size)
        let baseSize = self.boundingRect(with: CGSize(width: 2048, height: 2048),
                                         options: .usesLineFragmentOrigin,
                                         attributes: [.font: UIFont.systemFont(ofSize: size / 2)], context: nil).size
        let fontSize = outputImageSize.width / max(baseSize.width, baseSize.height) * (outputImageSize.width / 2)
        let font = UIFont.systemFont(ofSize: fontSize)
        let textSize = self.boundingRect(with: CGSize(width: outputImageSize.width, height: outputImageSize.height),
                                         options: .usesLineFragmentOrigin,
                                         attributes: [.font: font], context: nil).size
        
        let style = NSMutableParagraphStyle()
        style.alignment = NSTextAlignment.center
        style.lineBreakMode = NSLineBreakMode.byClipping
        
        let attr : [NSAttributedString.Key : Any] = [NSAttributedString.Key.font : font,
                                                     NSAttributedString.Key.paragraphStyle: style,
                                                     NSAttributedString.Key.backgroundColor: UIColor.clear ]
        
        UIGraphicsBeginImageContextWithOptions(outputImageSize, false, 0)
        self.draw(in: CGRect(x: (size - textSize.width) / 2,
                             y: (size - textSize.height) / 2,
                             width: textSize.width,
                             height: textSize.height),
                  withAttributes: attr)
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }
    
}

extension String {
    
    var timeStamp: String {
        let date = Date()
        let timeInterval = date.timeIntervalSince1970
        let millisecond = CLongLong(timeInterval * 1000)
        return "\(millisecond)"
    }
    
}

extension String {
    
    func getLastSeenString(replace withReplace: Bool) -> String {
        if let timeStamp = TimeInterval(self) {
            var result = ""
            let timestampDate = Date(timeIntervalSince1970: timeStamp)
            let currentDate = Date()
            let calendar = Calendar.current
            let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: timestampDate, to: currentDate)
            if let year = components.year, year > 0 {
                result = String(year) + (year == 1 ? " Year ago" : " Years ago")
            } else if let month = components.month, month > 0 {
                result = String(month) + (month == 1 ? " Month ago" : " Months ago")
            } else if let day = components.day, day > 0 {
                result = (day == 1 ? "yesterday" : String(day) + " Days ago")
            } else if let hour = components.hour, hour > 0 {
                result = String(hour) + (hour == 1 ? " Hour ago" : " Hours ago")
            } else if let minute = components.minute, minute > 0 {
                result = String(minute) + (minute == 1 ? " Minute ago" : " Minutes ago")
            } else {
                result = "Just now"
            }
            return withReplace ? replaceTime(result) : result
        } else {
            return self
        }
    }
    
    func replaceTime(_ input: String) -> String {
        var time = input.lowercased()
        if time.contains("hours ago") || time.contains("hour ago") {
            time = time.replacingOccurrences(of: "hours ago", with: "H")
            time = time.replacingOccurrences(of: "hour ago", with: "H")
        } else if time.contains("days ago") || time.contains("day ago") {
            time = time.replacingOccurrences(of: "days ago", with: "D")
            time = time.replacingOccurrences(of: "day ago", with: "D")
        } else if time.contains("months ago") || time.contains("month ago") {
            time = time.replacingOccurrences(of: "months ago", with: "M")
            time = time.replacingOccurrences(of: "month ago", with: "M")
        } else if time.contains("minutes ago") || time.contains("minute ago") {
            time = time.replacingOccurrences(of: "minutes ago", with: "Min")
            time = time.replacingOccurrences(of: "minute ago", with: "Min")
        } else if time.contains("year ago") || time.contains("years ago") {
            time = time.replacingOccurrences(of: "year ago", with: "Y")
            time = time.replacingOccurrences(of: "years ago", with: "Y")
        }
        return time
    }
    
}
