//
//  NXFundation+Ext.swift
//  NXFramework-Swift-Demo
//
//  Created by ak on 2020/10/26.
//  Copyright © 2020 NXFramework-Swift. All rights reserved.
//

import Foundation
import UIKit

public extension Date {
    var millisecondsSince1970: Int {
        return Int((timeIntervalSince1970 * 1000.0).rounded())
    }

    var secondsSince1970: Int {
        return Int(timeIntervalSince1970.rounded())
    }

    init(milliseconds: Int) {
        self = Date(timeIntervalSince1970: TimeInterval(milliseconds / 1000))
    }

    func getCurrentTimeString(_ format: String = "yyyy-MM-dd HH:mm:ss") -> String {
        let nowDate = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = format
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = Foundation.TimeZone(identifier: "UTC")
        // formatter.dateStyle = .MediumStyle
        // formatter.timeStyle = .MediumStyle
        return formatter.string(from: nowDate)
    }

    var iso8601: String {
        return Formatter.iso8601.string(from: self)
    }
}

public extension Formatter {
    static let iso8601: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .chinese)
        formatter.locale = Locale(identifier: "Asia/Shanghai")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
        return formatter
    }()
}

public extension String {
    var dateFromISO8601: Date? {
        return Formatter.iso8601.date(from: self)
    }

    func appendLineToURL(fileURL: URL) throws {
        try (self + "\n").appendToURL(fileURL: fileURL)
    }

    func appendToURL(fileURL: URL) throws {
        let data = self.data(using: String.Encoding.utf8)!
        try data.append2File(fileURL: fileURL)
    }

    ///
    func substring(to index: Int) -> String {
        guard let end_Index = validEndIndex(original: index) else {
            return self
        }
        return String(self[startIndex ..< end_Index])
    }

    ///
    func substring(from index: Int) -> String {
        guard let start_index = validStartIndex(original: index) else {
            return self
        }
        return String(self[start_index ..< endIndex])
    }

    ///
    func sliceString(_ range: CountableRange<Int>) -> String {
        guard
            let startIndex = validStartIndex(original: range.lowerBound),
            let endIndex = validEndIndex(original: range.upperBound),
            startIndex <= endIndex
        else {
            return ""
        }
        return String(self[startIndex ..< endIndex])
    }

    ///
    func sliceString(_ range: CountableClosedRange<Int>) -> String {
        guard
            let start_Index = validStartIndex(original: range.lowerBound),
            let end_Index = validEndIndex(original: range.upperBound),
            startIndex <= endIndex
        else {
            return ""
        }
        if endIndex.encodedOffset <= end_Index.encodedOffset {
            return String(self[start_Index ..< endIndex])
        }
        return String(self[start_Index ... end_Index])
    }

    private func validIndex(original: Int) -> String.Index {
        switch original {
        case ...startIndex.encodedOffset: return startIndex
        case endIndex.encodedOffset...: return endIndex
        default: return index(startIndex, offsetBy: original)
        }
    }

    private func validStartIndex(original: Int) -> String.Index? {
        guard original <= endIndex.encodedOffset else { return nil }
        return validIndex(original: original)
    }

    private func validEndIndex(original: Int) -> String.Index? {
        guard original >= startIndex.encodedOffset else { return nil }
        return validIndex(original: original)
    }

    ///
    func toDate(formatter: String) -> Date {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale.current
        dateFormatter.dateFormat = formatter
        let date = dateFormatter.date(from: self)
        return date!
    }
}

extension Data {
    func append2File(fileURL: URL) throws {
        if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
            defer {
                fileHandle.closeFile()
            }
            fileHandle.seekToEndOfFile()
            fileHandle.write(self)
        } else {
            try write(to: fileURL, options: .atomic)
        }
    }
}

public extension UInt32 {
    var double: Double {
        return Double(self)
    }
}

public extension UIApplication {
    class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }
}
