import Foundation

extension String {
    var alphanumeric: String {
        return self.components(separatedBy: CharacterSet.alphanumerics.inverted).joined().lowercased()
    }
    
    var numeric: String {
        return self.alphanumeric.components(separatedBy: CharacterSet.letters).joined()
    }
    
    var removeHTML: String {
        let encodedString = self
        let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
        ]

        guard let data = encodedString.data(using: .utf8),
              let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else {
            return self
        }
        
        return attributedString.string
    }
}

extension NumberFormatter {
    static let currency: NumberFormatter = {
        let numberFormatter = NumberFormatter()
        numberFormatter.alwaysShowsDecimalSeparator = false
        numberFormatter.numberStyle = .currency
        numberFormatter.locale = Locale.current
        return numberFormatter
    }()
    
    static func currencyString(_ amount: Double) -> String {
        let formatter = Self.currency
        
        if amount.rounded() == amount {
            formatter.minimumFractionDigits = 0
        } else {
            formatter.minimumFractionDigits = 2
        }
        
        return formatter.string(from: NSNumber(value: amount)) ?? "$\(amount)"
    }
    
    static let postcodeFormatter: NumberFormatter = {
        var nf = NumberFormatter()
        nf.numberStyle = .decimal
        nf.maximumFractionDigits = 0
        nf.minimumIntegerDigits = 4
        nf.maximumIntegerDigits = 4
        nf.usesGroupingSeparator = false
        return nf
    }()
}


extension DateFormatter {
    static let dateRequest: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        return dateFormatter
    }()
    
    static let short: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "d MMMM"
        return dateFormatter
    }()
    
    static let long: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "d MMMM yyyy"
        return dateFormatter
    }()
    
    static let calendar: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .full
        dateFormatter.timeStyle = .none
        return dateFormatter
    }()
    
    static let time: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = ""
        dateFormatter.timeStyle = .short
        return dateFormatter
    }()
    
    static let shortDayName: DateFormatter = {
       let formatter = DateFormatter()
        formatter.dateFormat = "EEEEEE"
        return formatter
    }()
    
    static let dayNumber: DateFormatter = {
       let formatter = DateFormatter()
        formatter.dateFormat = "d"
        return formatter
    }()
}

extension Sequence {
    func asyncMap<T>(
        _ transform: (Element) async throws -> T
    ) async rethrows -> [T] {
        var values = [T]()

        for element in self {
            try await values.append(transform(element))
        }

        return values
    }
}

extension Array where Element: Hashable {
    func unique() -> Self {
        var seen = Set<Element>()
        return filter{ seen.insert($0).inserted }
    }
}

extension Bundle {
    static var versionNumber: String {
        guard let infoDict = Bundle.main.infoDictionary,
              let appName = infoDict["CFBundleName"] as? String,
              let version = infoDict["CFBundleShortVersionString"] as? String,
              let build = infoDict["CFBundleVersion"] as? String
        else {
            return "Unknown"
        }
        
        return "\(appName) v\(version) (\(build))"
    }
}
