//
//  LocationManager.swift
//  1Weather
//
//  Created by Demid Merzlyakov on 20.02.2021.
//

import Foundation

public protocol LocationManagerDelegate: class {
    func locationManager(_ locationManager: LocationManager, changedCurrentLocation newLocation: Location?)
}

public class LocationManager {
    private let log = Logger(componentName: "LocationManager")
    private let delegates = MulticastDelegate<LocationManagerDelegate>()
    private let weatherUpdateSource: WeatherSource
    private let defaultLocation = Location(lastTimeUpdated: Date(),
                                           coordinates: .init(latitude: 37.3230, longitude: -122.0322), // Cupertino
                                           timeZone: TimeZone(abbreviation: "PST")!)
    private var _currentLocation: Location? {
        didSet {
            if oldValue?.description != currentLocation?.description {
                log.info("Current location changed to: \(currentLocation?.description ?? "nil")")
            }
            log.info("Location updated.")
            delegates.invoke { [weak self] (delegate) in
                guard let self = self else { return }
                delegate.locationManager(self, changedCurrentLocation: currentLocation)
            }
        }
    }
    
    public static let shared = LocationManager(weatherUpdateSource: WdtWeatherSource())
    
    public init(weatherUpdateSource: WeatherSource) {
        self.weatherUpdateSource = weatherUpdateSource
    }
    
    public var currentLocation: Location? {
        get {
            guard let location = _currentLocation else {
                return defaultLocation
            }
            
            return location
        }
        
        set {
            _currentLocation = newValue
        }
    }
    
    public func updateWeather() {
        guard let location = currentLocation else {
            log.warning("Update weather: no location.")
            return
        }
        log.info("Update weather for location: \(location)")
        weatherUpdateSource.updateWeather(for: location) { [weak self] (updatedLocation, error) in
            guard let self = self else { return }
            guard let updatedLocation = updatedLocation else {
                if let error = error {
                    self.log.error("Update weather error: \(error)")
                }
                else {
                    self.log.error("Update weather error: unknown error")
                }
                return
            }
            
            DispatchQueue.main.async {
                self.currentLocation = updatedLocation
            }
        }
    }
    
    public func add(delegate: LocationManagerDelegate) {
        delegates.add(delegate: delegate)
    }
    
    public func remove(delegate: LocationManagerDelegate) {
        delegates.remove(delegate: delegate)
    }
}
