//
//  WdtSurfaceObservation.swift
//  1Weather
//
//  Created by Demid Merzlyakov on 25.02.2021.
//

import Foundation

struct WdtSurfaceObservation: Codable {
    public var dateTimeLocal: String
    public var weekDay: String
    public var dayNight: String
    
    public var tempF: String? // Currently XMLCoder seems to struggle with decoding optional doubles with an empty value: <temp_F></temp_F> won't be decoded as nil, instead decoding will fail. So, using Strings for now.
    public var apparentTempF: String?
    public var windSpeedKph: String?
    public var windDirection: String?
    public var pressureMb: String?
    public var visibilityFt: String?
    public var humidity: String?
    public var weatherCode: String?
    public var sunriseLocalTime: String?
    public var sunsetLocalTime: String?
    
    private enum CodingKeys: String, CodingKey {
        case dateTimeLocal = "ob_time"
        case weekDay = "day_of_week_local"
        case dayNight = "day_night"
        
        case tempF = "temp_F"
        case apparentTempF = "apparent_temp_F"
        case windSpeedKph = "wnd_spd_kph"
        case windDirection = "wnd_dir"
        case pressureMb = "press_mb"
        case visibilityFt = "visibility_ft"
        case humidity = "rh_pct"
        case weatherCode = "wx_code"
        case sunriseLocalTime = "sunrise_local"
        case sunsetLocalTime = "sunset_local"
    }
    
    private static let log = Logger(componentName: "WdtSurfaceObservation")
    
    public func toAppModel(timeZone: TimeZone, updatedAt: Date) -> CurrentWeather? {
        let log = WdtSurfaceObservation.log
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        dateFormatter.timeZone = timeZone
        
        guard let date = dateFormatter.date(from: self.dateTimeLocal) else {
            log.error("failed to parse date from: \(self.dateTimeLocal)")
            return nil
        }
        var weekDay = WeekDay(rawValue: self.weekDay)
        if weekDay == nil {
            var calendar = Calendar(identifier: .gregorian)
            calendar.timeZone = timeZone
            weekDay = WeekDay(grigorianWeekDayNumber: calendar.component(.weekday, from: date))
        }
        guard let weekDayUnwrapped = weekDay else {
            log.error("Couldn't parse weekDay from: \(self.weekDay)")
            return nil
        }
        
        let isDay = dayNight.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == "day"
        
        var result = CurrentWeather(lastTimeUpdated: updatedAt, date: date, timeZone: timeZone, weekDay: weekDayUnwrapped, isDay: isDay)
        if let weatherCode = self.weatherCode {
            result.type = WdtWeatherCode(rawValue: weatherCode)?.toAppModel() ?? .unknown
        }
        
        result.windSpeed = WindSpeed(valueString: self.windSpeedKph, unit: .kilometersPerHour)
        result.windDirection = WindDirection(rawValue: windDirection ?? "")
        result.temp = Temperature(valueString: tempF, unit: .fahrenheit)
        result.apparentTemp = Temperature(valueString: apparentTempF, unit: .fahrenheit)
        if let humidity = Percent(self.humidity ?? ""), humidity >= 0, humidity <= 100 {
            result.humidity = humidity
        }
        result.visibility = Visibility(valueString: visibilityFt, unit: .feet)
        result.pressure = Pressure(valueString: pressureMb, unit: .millibars)
        
        // Doesn't it make life great when the server sends local time, but doesn't send a timezone?
        if let localDateWithoutTime = dateTimeLocal.split(separator: " ").first {
            if let sunriseLocalTime = self.sunriseLocalTime, let sunsetLocalTime = self.sunsetLocalTime {
                let sunriseLocalDateTime = "\(localDateWithoutTime) \(sunriseLocalTime)"
                let sunsetLocalDateTime = "\(localDateWithoutTime) \(sunsetLocalTime)"
                
                let sunDateFormatter = DateFormatter()
                sunDateFormatter.timeZone = timeZone
                sunDateFormatter.dateFormat = "yyyy-MM-dd hh:mm a"
                result.sunrise = sunDateFormatter.date(from: sunriseLocalDateTime)
                result.sunset = sunDateFormatter.date(from: sunsetLocalDateTime)
            }
        }
        
        return result
    }
}
