//
//  Defines.swift
//  1Weather
//
//  Created by Demid Merzlyakov on 02.12.2020.
//

import Foundation

//MARK: - Algolia keys

let kAlgoliaAppId: String = "plSP1L2N5P5J"
let kAlgoliaAPIKey: String = "c211961220dc98074f14bc7ac1281cdd"

let DEGREES = "\u{00B0}"
let INCHES = "\u{2033}"
let PRESSURE_FALLING = "\u{25BC}"
let PRESSURE_RISING = "\u{25B2}"
let MILLIMETERS = "mm"
let BLANK = "--"
let UP_ARROW = "\u{2191}"
let DOWN_ARROW = "\u{2193}"

func windUnits() -> WindUnits {
    return .mps
}

func pressureUnits() -> PressureUnits {
    return .mmhg
}

func distanceUnits() -> DistanceUnits {
    return .kilometers
}

enum DistanceUnits: Int {
    case miles, kilometers
    
    static let desc = ["Miles (mi)".localized, "Kilometers (km)".localized]
}

extension String {
    func localized(comment: String? = nil) -> String {
        return NSLocalizedString(self, comment: comment ?? self)
    }
    var localized: String {
        return NSLocalizedString(self, comment: self)
    }
    
    func trim() -> String {
        return self.trimmingCharacters(in: CharacterSet.whitespaces)
    }

    func trimSpaceNewlines() -> String {
        return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
    }

    func trim(_ characters: String) -> String {
        return self.trimmingCharacters(in: CharacterSet(charactersIn: characters))
    }

}

func isMetric() -> Bool {
    return true
}

extension Double {

    func roundTo(_ numberOfPlaces: Int) -> Double {
        let divisor = pow(10.0, Double(numberOfPlaces))
        return (self * divisor).rounded() / divisor
    }
}

public extension Date {

    init(dateString: String) {
        let dateStringFormatter = DateFormatter()
        dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US") as Locale
        dateStringFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        //        dateStringFormatter.timeZone = NSTimeZone(name: "GMT")
        if let date = dateStringFormatter.date(from: dateString) {
            self.init(timeInterval: 0, since: date)
        } else {
            self.init()
        }
    }

    init(utcDateString: String) {
        let dateStringFormatter = DateFormatter()
        dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US") as Locale
        dateStringFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        dateStringFormatter.timeZone = TimeZone(abbreviation: "UTC")
        if let date = dateStringFormatter.date(from: utcDateString) {
            self.init(timeInterval: 0, since: date)
        } else {
            self.init()
        }
    }

    init(dateString: String, format: String) {
        let dateStringFormatter = DateFormatter()
        dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US") as Locale
        //        dateStringFormatter.timeZone = NSTimeZone(name: "GMT")
        dateStringFormatter.dateFormat = format
        dateStringFormatter.isLenient = true

        if let date = dateStringFormatter.date(from: dateString) {
            self.init(timeInterval: 0, since: date)
        } else {
            self.init()
        }
    }
    
    func getDayPart() -> String {
        let dateFormatter = DateFormatter()
        let localeFormatString = DateFormatter.dateFormat(fromTemplate: "MMM dd", options: 0, locale: dateFormatter.locale)
        dateFormatter.dateFormat = localeFormatString
        let str = dateFormatter.string(from: self)
        return str

        //        formatter.dateStyle = .ShortStyle
        //        formatter.dateFormat = "MMM dd"

        //        return formatter.stringFromDate(self)
    }

    func getTimePart() -> String {
        let dateFormatter = DateFormatter()
        let localeFormatString = DateFormatter.dateFormat(fromTemplate: "j:m a", options: 0, locale: dateFormatter.locale)
        dateFormatter.dateFormat = localeFormatString
        var str = dateFormatter.string(from: self)
        if str.hasSuffix("AM") || str.hasSuffix("PM") {
            // this is a kludge to return 10 PM instead of 10:00 PM which above gives.
            // non-US format (23 hour) above returns 22:00
            let localeFormatString = DateFormatter.dateFormat(fromTemplate: "j a", options: 0, locale: dateFormatter.locale)
            dateFormatter.dateFormat = localeFormatString
            str = dateFormatter.string(from: self)
        }
        return str
    }

    func getTimePartFull() -> String {
        let dateFormatter = DateFormatter()
        let localeFormatString = DateFormatter.dateFormat(fromTemplate: "j:m a", options: 0, locale: dateFormatter.locale)
        dateFormatter.dateFormat = localeFormatString
        let str = dateFormatter.string(from: self)

        return str
    }

    func getWithFormat(_ format: String) -> String {
        let dateFormatter = DateFormatter()
        let localeFormatString = DateFormatter.dateFormat(fromTemplate: format, options: 0, locale: dateFormatter.locale)
        dateFormatter.dateFormat = localeFormatString
        let str = dateFormatter.string(from: self)
        return str
    }

    func getTimePart(_ timeZone: String) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.timeZone = TimeZone(identifier: timeZone)

        let localeFormatString = DateFormatter.dateFormat(fromTemplate: "j:m a", options: 0, locale: dateFormatter.locale)
        dateFormatter.dateFormat = localeFormatString
        let str = dateFormatter.string(from: self)

        return str
    }

    // Return an iso 8601 formatted date
    var iso8601: String {
        return Formatter.iso8601.string(from: self)
    }
}


extension Formatter {

    // creates a formatter that creates a string in this format
    // "2017-03-22T13:22:13.933Z"
    public static let iso8601: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
        return formatter
    }()
}


enum WindUnits: Int {
    case mph, kph, mps, knots, beaufort
    
    static let desc = ["Miles per hour (mph)".localized, "Kilometers per hour (km/h)".localized, "Meters per second (m/s)".localized, "Knots (kn)".localized, "Beaufont scale".localized]
    
    func windSpeed(_ mph: String, kph: String) -> String {
        switch self {
        case .mph:
            return "\(mph) MPH"
        case .kph:
            return "\(kph) KM/H"
        case .mps:
            return "\(kphToMps(kph)) M/S"
        case .knots:
            return "\(kphToKnots(kph)) KNOTS"
        case .beaufort:
            return "\(mphToBeaufort(mph))"
        }
    }
    
    func kphToMps(_ valueKph: String) -> String  {
        if let dvalue = Double(valueKph) {
            return String((dvalue * 0.277778).roundTo(1))
        }
        return valueKph
    }
    
    func kphToKnots(_ valueKph: String) -> String  {
        if let dvalue = Double(valueKph) {
            return String(format:"%.0f", (dvalue * 0.539957).roundTo(0))
            
        }
        
        return valueKph
    }
    
    func mphToBeaufort(_ valueMph: String) -> String  {
        if let mph = Int(valueMph) {
            if mph < 1 {
                return "0"
            } else if mph < 3 {
                return "1"
            } else if mph < 7 {
                return "2"
            } else if mph < 11 {
                return "3"
            } else if mph < 18 {
                return "4"
            } else if mph < 24 {
                return "5"
            } else if mph < 31 {
                return "6"
            } else if mph < 38 {
                return "7"
            } else if mph < 46 {
                return "8"
            } else if mph < 54 {
                return "9"
            } else if mph < 63 {
                return "10"
            } else if mph < 74 {
                return "11"
            } else  {
                return "12"
            }
        }
        return valueMph
    }
}

enum PressureUnits: Int {
    case inches, mb, mmhg, atm, kpa
    
    static let desc = ["Inches of mercury (\")".localized, "Millibars (mb)".localized, "Millimeters of mercury (mm)".localized, "Atmosphere (atm)".localized, "Kilopascal (kPa)".localized]
    
    func pressure(_ inches: String, mb: String, tendency: String, accessibility: Bool = false) -> String {
        var tStr = ""
        let t = tendency.lowercased()
        if t == "falling" {
            tStr = accessibility ? "falling" : PRESSURE_FALLING
        } else if t == "rising" {
            tStr = accessibility ? "rising" : PRESSURE_RISING
        }

        switch self {
        case .inches:
            return ("\(inches)\"\(tStr)")
        case .mb:
            return ("\(formatPressureMb(mb))\(tStr)MB")
        case .mmhg:
            return ("\(inchesMercuryToMmHg(inches))\(tStr)MMHG")
        case .atm:
            return ("\(inchesMercuryToAtmosphere(inches))\(tStr)ATM")
        case .kpa:
            return ("\(inchesMercuryToKilopascal(inches))\(tStr)KPA")
        }
    }
    
    func inchesMercuryToMmHg(_ inchesMercury: String) -> String  {
        if let dvalue = Double(inchesMercury) {
            return String(format:"%.0f", (dvalue * 25.399999705).roundTo(0))
        }
        return inchesMercury
    }
    
    func inchesMercuryToAtmosphere(_ inchesMercury: String) -> String  {
        if let dvalue = Double(inchesMercury) {
            return String((dvalue / 29.9212583001).roundTo(2))
        }
        return inchesMercury
    }
    
    func inchesMercuryToKilopascal(_ inchesMercury: String) -> String  {
        if let dvalue = Double(inchesMercury) {
            return String((dvalue * 3.3863886667).roundTo(2))
        }
        return inchesMercury
    }
    
    func formatPressureMb(_ pressureMb: String) -> String  {
        if let dvalue = Double(pressureMb) {
            return String(format:"%.0f", dvalue.roundTo(0))
        }
        return pressureMb
    }
}
