import UIKit
import CoreLocation

class RTNMapsGLView: UIView {
    var styleUrl: String?
    var aerisId: String?
    var aerisSecretKey: String?
    var mapboxAccessToken: String?
    var mapView: MapsGLView!
    var mapLayerState: NSDictionary?
    var pendingMapLayerState: NSDictionary?
    var selectedPin: NSDictionary?
    var pendingSelectedPin: NSDictionary?
    var userLocation: NSArray?
    var mapLoaded = false
    var legendView: MapsGLLegendView!
    let toolbarView = MapToolbarView()
    private var optionsController: UINavigationController!
    @objc var onMapsglViewDidLoad: RCTBubblingEventBlock?
    @objc var onMapsglViewDidMove: RCTBubblingEventBlock?
    @objc var onSelectWaterbody: RCTBubblingEventBlock?

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    private func setupView() {
        if let aerisId = aerisId, let aerisSecretKey = aerisSecretKey, let mapboxAccessToken = mapboxAccessToken {
            // Initialize and configure the Mapbox MapsGL webivew
            let account = MapsGLAccount(id: aerisId, secret: aerisSecretKey, mapboxToken: mapboxAccessToken)
            var configuration = MapsGLConfiguration(account: account)
            configuration.animation.pauseWhileLoading = true
            if let userLocation = userLocation {
                if userLocation.count >= 2,
                    let latitude = userLocation[1] as? Double,
                    let longitude = userLocation[0] as? Double {
                    configuration.centerCoordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
                } else {
                    print("Invalid user location")
                }
            } else {
                configuration.centerCoordinate = CLLocationCoordinate2D(latitude: 35, longitude: -90)
            }
            configuration.zoomLevel = 7
            
            mapView = MapsGLView(config: configuration, frame: bounds)
            mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            mapView.delegate = self
            addSubview(mapView)
            
//            toolbarView.playButton.isEnabled = false
//            toolbarView.playButton.addTarget(mapView, action: #selector(MapsGLView.toggle), for: .touchUpInside)
//            toolbarView.layersButton.addTarget(self, action: #selector(showOptions), for: .touchUpInside)
//            toolbarView.translatesAutoresizingMaskIntoConstraints = false
//            addSubview(toolbarView)

//            NSLayoutConstraint.activate([
//                legendView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
//                legendView.centerXAnchor.constraint(equalTo: centerXAnchor),
//                legendView.widthAnchor.constraint(equalToConstant: 300),
//                toolbarView.centerXAnchor.constraint(equalTo: centerXAnchor),
//                toolbarView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor),
//                toolbarView.heightAnchor.constraint(equalToConstant: 44)
//            ])
            
            let optionsController = MapOptionsViewController()
            optionsController.delegate = self
            
            let optionsNavigationController = UINavigationController(rootViewController: optionsController)
            if #available(iOS 15, *) {
                let appearance = UINavigationBarAppearance()
                appearance.configureWithOpaqueBackground()
                optionsNavigationController.navigationBar.standardAppearance = appearance
                optionsNavigationController.navigationBar.scrollEdgeAppearance = appearance
            }
            self.optionsController = optionsNavigationController
            
            mapLoaded = true
            if let pendingMapLayerState = self.pendingMapLayerState {
                print("Connor - updating map layer state with pending value")
                mapView.setMapLayerState(pendingMapLayerState)
                self.pendingMapLayerState = nil
            }
            if let selectedPin = self.selectedPin {
                mapView.setSelectedPin(selectedPin)
                self.pendingSelectedPin = nil
            }
        }
    }

    @objc func showOptions() {
        // Check if the superview is a view controller
        guard let viewController = findViewController() else {
            return
        }
        
        viewController.present(optionsController, animated: true)
    }
    
    private func findViewController() -> UIViewController? {
        var responder: UIResponder? = self
        while let currentResponder = responder {
            if let viewController = currentResponder as? UIViewController {
                return viewController
            }
            responder = currentResponder.next
        }
        return nil
    }
    
    @objc func setAerisId(_ val: NSString) {
        self.aerisId = val as String
        setupView()
    }
    
    @objc func setAerisSecretKey(_ val: NSString) {
        self.aerisSecretKey = val as String
        setupView()
    }
    
    @objc func setMapboxAccessToken(_ val: NSString) {
        self.mapboxAccessToken = val as String
        setupView()
    }
    
    @objc func setMapLayerState(_ val: NSDictionary) {
        if let mapView = mapView {
            if mapLoaded {
                mapView.setMapLayerState(val)
            }
        } else {
            // Store the val in an instance variable
            // Call setMapLayerState when the map finishes loading
            self.pendingMapLayerState = val
        }
    }
    
    @objc func setPins(_ val: NSArray?) {
        if let mapView = mapView {
            mapView.updatePins(val)
        }
    }

    @objc func setSelectedPin(_ val: NSDictionary?) {   
        if let mapView = mapView {
            if mapLoaded {
                mapView.setSelectedPin(val)
            }
        } else {
            // Store the val in an instance variable
            // Call setSelectedPin when the map finishes loading
            self.pendingSelectedPin = val
        }
    }
    
    @objc func setStyleUrl(_ val: String?) {
        if let mapView = mapView, let styleUrl = val {
            mapView.updateStyleUrl(styleUrl)
        }
    }
    
    @objc func setUserLocation(_ val: NSArray) {
        if let location = RCTConvert.nsArray(val) {
            self.userLocation = location as NSArray?
        } else {
            self.userLocation = nil // Handle undefined value
        }
    }
}

extension RTNMapsGLView: MapOptionsViewControllerDelegate {
    func mapOptionsViewControllerDidAddLayers(layers: [String]) {
        for layer in layers {
            mapView.addWeatherLayer(layer)
        }
    }
    
    func mapOptionsViewControllerDidRemoveLayers(layers: [String]) {
        for layer in layers {
            mapView.removeWeatherLayer(layer)
        }
    }
}

extension RTNMapsGLView: MapsGLViewDelegate {
    
    func selectWaterbody(waterbody: AnyObject) {
        onSelectWaterbody?(["waterbody": waterbody])
    }
    
    func mapsglViewDidMove(mapView: MapsGLView, event: AnyObject) {
        onMapsglViewDidMove?(["mapView": event])
    }
    
    func mapsglViewDidLoad(mapView: MapsGLView) {
        print("CONNOR - mapsglViewDidLoad")
        (onMapsglViewDidLoad ?? nil)!([:])
        
        mapView.getTimelineCurrentDate { [weak self] date in
            self?.toolbarView.update(date: date)
        }
        
//        mapView.addWeatherLayer("temperatures", options: [
//            "paint": [
//                "sample": [
//                    "colorscale": [
//                        "interval": 5
//                    ]
//                ]
//            ]
//        ])
//        mapView.addWeatherLayer("wind-dir")
//        mapView.addWeatherLayer("wind-particles")
        
        mapView.getBounds { bounds in
            mapView.getZoom { zoom in
                
                let boundsDict: [String: Any] = [
                    "north": bounds.northwest.latitude,
                    "south": bounds.southeast.latitude,
                    "east": bounds.southeast.longitude,
                    "west": bounds.northwest.longitude,
                ]
                
                self.onMapsglViewDidLoad?([ "mapView": ["bounds": boundsDict, "zoom": zoom] as [String : Any] ])
            }
        }
//        mapView.getCenter { center in
//            print(center)
//        }

//        mapView.setCenter(CLLocationCoordinate2D(latitude: 47.5, longitude: -121.5))
//        mapView.setZoom(2)
        
    }
    
    func mapsglViewDidReceiveClick(mapView: MapsGLView, coordinate: CLLocationCoordinate2D) {
        mapView.query(coordinate: coordinate) { result in
            print("Query result: \(String(describing: result))")
        }
    }
    
    func mapsglViewDidUpdateLayers(mapView: MapsGLView) {
        toolbarView.playButton.isEnabled = mapView.activeLayers.count > 0
    }
    
    func mapsglViewDidUpdateLegends(mapView: MapsGLView) {
        mapView.updateLegends()
    }

    func mapsglViewDidAddLayer(mapView: MapsGLView, layer: String) {
    }

    func mapsglViewDidRemoveLayer(mapView: MapsGLView, layer: String) {
    }

    func mapsglViewDidAddSource(mapView: MapsGLView, source: String) {
    }
    
    func mapsglViewDidRemoveSource(mapView: MapsGLView, source: String) {
    }
    
    func mapsglViewDidStartLoading(mapView: MapsGLView) {
        toolbarView.activityIndicator.startAnimating()
    }
    
    func mapsglViewDidCompleteLoading(mapView: MapsGLView) {
        toolbarView.activityIndicator.stopAnimating()
    }
    
    func mapsglViewDidStartAnimating(mapView: MapsGLView) {
        toolbarView.playButton.isSelected = true
    }
    
    func mapsglViewDidStopAnimating(mapView: MapsGLView) {
        toolbarView.playButton.isSelected = false
    }
    
    func mapsglViewDidAdvanceAnimation(mapView: MapsGLView, progress: Double, date: Date) {
        toolbarView.update(date: date)
    }
}
