//
//  NSString+Ex.swift
//  TSLiveWallpaper
//
//  Created by 100Years on 2024/12/20.
//
import CommonCrypto
extension String {
    
    var color: UIColor {
        if isEmpty {
            return .clear
        }
        return UIColor.fromHex(self)
    }
    
    var localFilePath: String {
        var path = self
        if path.lowercased().hasPrefix("file://") {
            path.removeFirst("file://".count)
        }
        return path
    }
    
    func toCgRect() -> CGRect {
        NSCoder.cgRect(for: self)
    }
    
    func toCgPoint() -> CGPoint {
        NSCoder.cgPoint(for: self)
    }


    func toRgba() -> (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat)? {
        var r:CGFloat = 0;
        var g:CGFloat = 0;
        var b:CGFloat = 0;
        var a:CGFloat = 0;
        var prefix: Int = 0;

        let color: String = trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
        if (color.hasPrefix("#")) {
            prefix = 1
        }
        else if (color.hasPrefix("0X")) {
            prefix = 2
        }
        let length: Int = color.count - prefix
        //         RGB            RGBA          RRGGBB        RRGGBBAA
        
        func componentFrom(string: String, start: Int, length: Int) -> CGFloat {
            guard start >= 0, start + length <= string.count else {
                return 0
            }
            
            let begin = string.index(startIndex, offsetBy: start)
            let end = string.index(startIndex, offsetBy: start + length)
            
            let sub = string[begin..<end]
            var full = String(sub)
            if length == 1 {
                full += full
            }
            
            var hex: UInt64 = 0
            Scanner(string: full).scanHexInt64(&hex)
            
            let float = CGFloat(hex) / 255.0
            return float
        }
        
        switch length {
        case 3: // RGB
            r = componentFrom(string: color, start: prefix, length: 1)
            g = componentFrom(string: color, start: prefix + 1, length: 1)
            b = componentFrom(string: color, start: prefix + 2, length: 1)
            a = 1
        case 4: // RGBA
            r = componentFrom(string: color, start: prefix, length: 1)
            g = componentFrom(string: color, start: prefix + 1, length: 1)
            b = componentFrom(string: color, start: prefix + 2, length: 1)
            a = componentFrom(string: color, start: prefix + 3, length: 1)
        case 6: // RRGGBB
            r = componentFrom(string: color, start: prefix, length: 2)
            g = componentFrom(string: color, start: prefix + 2, length: 2)
            b = componentFrom(string: color, start: prefix + 4, length: 2)
            a = 1
        case 8: // RRGGBBAA
            r = componentFrom(string: color, start: prefix, length: 2)
            g = componentFrom(string: color, start: prefix + 2, length: 2)
            b = componentFrom(string: color, start: prefix + 4, length: 2)
            a = componentFrom(string: color, start: prefix + 6, length: 2)
        default:
            return nil
        }
        
        return (r, g, b, a)

    }
    
    func toColor() -> UIColor? {
        if let rgba = toRgba() {
            return UIColor(red: rgba.r, green: rgba.g, blue: rgba.b, alpha: rgba.a)
        }
        
        return nil
    }
}

extension String {
    
    var localized:String{
        return self
//        return NSLocalizedString(self, comment: self)
    }
}


extension String {
    var doubleValue: Double? {
        Double(self)
    }
    
    var localNumber: String {
        if let value = Int(self), let numberString = value.localNumber {
            return numberString
        }
        return self
    }
    
    var md5:String {
        let data = Data(self.utf8)
        var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        data.withUnsafeBytes {
            _ = CC_MD5($0.baseAddress, CC_LONG(data.count), &digest)
        }
        return digest.map { String(format: "%02x", $0) }.joined()
    }
}


extension String {
    // 移除逗号
    func deleteDotSymbol() -> String {
        // 超过1000的数字,格式化成文本后会带 ','(en)/'٬'(ar)
        return replacingOccurrences(of: ",", with: "").replacingOccurrences(of: "٬", with: "")
    }
    
}




extension String {
    /// 根据字符串动态创建类实例
    /// - Parameters:
    ///   - type: 要创建的类类型（泛型）
    ///   - bundle: 模块的命名空间（默认为 `nil`，即当前模块）
    /// - Returns: 创建的实例或 `nil`
    func toInstance<T:NSObject>(of type: T.Type, bundle: String? = nil) -> T? {
        // 获取完整的类名
        let namespace = bundle ?? Bundle.main.infoDictionary?["CFBundleName"] as? String ?? ""
        let className = "\(namespace).\(self)"
        
        // 通过类名获取类型
        guard let targetClass = NSClassFromString(className) as? T.Type else {
            return nil
        }
        
        // 创建实例
        return targetClass.init()
        
    }
    
    
    func toClass(bundle: String? = nil) -> AnyClass? {
        // 获取完整的类名
        let namespace = bundle ?? Bundle.main.infoDictionary?["CFBundleName"] as? String ?? ""
        let className = "\(namespace).\(self)"
        
        // 通过类名获取类型
        guard let targetClass = NSClassFromString(className) else {
            return nil
        }
        
        // 创建实例
        return targetClass
    }
}




extension String {
    

    func boundingRect(ofAttributes attributes: [NSAttributedString.Key: Any], size: CGSize) -> CGRect {
        let boundingBox = boundingRect(
            with: size,
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            attributes: attributes,
            context: nil
        )
        return boundingBox
    }
    
    func size(ofAttributes attributes: [NSAttributedString.Key: Any], maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
        boundingRect(ofAttributes: attributes, size: .init(width: maxWidth, height: maxHeight)).size
    }
    
    func size(ofFont font: UIFont, maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
        let constraintRect = CGSize(width: maxWidth, height: maxHeight)
        let boundingBox = boundingRect(
            with: constraintRect,
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            attributes: [.font: font],
            context: nil
        )
        return boundingBox.size
    }
    
    func width(ofSize size: CGFloat, maxHeight: CGFloat) -> CGFloat {
        width(
            ofFont: UIFont.systemFont(ofSize: size),
            maxHeight: maxHeight
        )
    }
    
    func width(ofFont font: UIFont, maxHeight: CGFloat) -> CGFloat {
        size(
            ofAttributes: [NSAttributedString.Key.font: font],
            maxWidth: CGFloat(MAXFLOAT),
            maxHeight: maxHeight
        ).width
    }
    
    func height(ofSize size: CGFloat, maxWidth: CGFloat) -> CGFloat {
        height(
            ofFont: UIFont.systemFont(ofSize: size),
            maxWidth: maxWidth
        )
    }
    
    func height(ofFont font: UIFont, maxWidth: CGFloat) -> CGFloat {
        size(
            ofAttributes: [NSAttributedString.Key.font: font],
            maxWidth: maxWidth,
            maxHeight: CGFloat(MAXFLOAT)
        ).height
    }
    
    subscript(_ indexs: ClosedRange<Int>) -> String {
            let beginIndex = index(startIndex, offsetBy: indexs.lowerBound)
            let endIndex = index(startIndex, offsetBy: indexs.upperBound)
            return String(self[beginIndex...endIndex])
        }
        
    subscript(_ indexs: Range<Int>) -> String {
        let beginIndex = index(startIndex, offsetBy: indexs.lowerBound)
        let endIndex = index(startIndex, offsetBy: indexs.upperBound)
        return String(self[beginIndex..<endIndex])
    }
    
    subscript(_ indexs: PartialRangeThrough<Int>) -> String {
        let endIndex = index(startIndex, offsetBy: indexs.upperBound)
        return String(self[startIndex...endIndex])
    }
    
    subscript(_ indexs: PartialRangeFrom<Int>) -> String {
        let beginIndex = index(startIndex, offsetBy: indexs.lowerBound)
        return String(self[beginIndex..<endIndex])
    }
    
    subscript(_ indexs: PartialRangeUpTo<Int>) -> String {
        let endIndex = index(startIndex, offsetBy: indexs.upperBound)
        return String(self[startIndex..<endIndex])
    }
    
    var assetFormat: String? {
        let lowercased = lowercased()
        if lowercased.hasSuffix("heic") {
            return "heic"
        }
        if lowercased.hasSuffix("jpg") || lowercased.hasSuffix("jpeg") {
            return "jpeg"
        }
        if lowercased.hasSuffix("png") {
            return "png"
        }
        if lowercased.hasSuffix("gif") {
            return "gif"
        }
        return nil
    }
}
