//
//  ForecastViewController.swift
//  1Weather
//
//  Created by Dmitry Stepanets on 08.02.2021.
//

import UIKit

class ForecastViewController: UIViewController {
    //Private
    private let forecastCellFactory:ForecastCellFactory
    private let cityButton = NavigationCityButton()
    private let daysControlView = DaysControlView()
    private let timePeriodControl = ForecastTimePeriodControl(items: ["forecast.timePeriod.daily".localized(),
                                                                      "forecast.timePeriod.hourly".localized()])
    private let tableView = UITableView()
    private let viewModel:ForecastViewModel
    private var timePeriodCellFrame = CGRect.zero
    private var localizationObserver:Any?
    private var timePeriod:TimePeriod {
        return TimePeriod(rawValue: timePeriodControl.selectedSegmentIndex) ?? .daily
    }
    
    init(viewModel: ForecastViewModel) {
        self.viewModel = viewModel
        self.forecastCellFactory = ForecastCellFactory(viewModel: viewModel)
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        viewModel.delegate = self
        viewModel.offsetHolder.delegate = self
        
        prepareViewController()
        prepareNavigationBar()
        prepareTableView()
        prepareTimePeriodControl()
        prepareDayControlsView()
        
        refreshCityButton()
        refreshDayButtons()
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.tableView.layoutTableHeaderView()
    }
    
    private func refreshCityButton() {
        cityButton.configure(with: viewModel.location)
        cityButton.isHidden = false
    }
    
    private func refreshDayButtons() {
        if let dailyWeather = viewModel.location?.daily {
            daysControlView.configure(dailyWeather: dailyWeather)
        }
        else {
            daysControlView.alpha = 0
        }
    }
    
    @objc private func handleSegmentDidChange() {
        guard let timePeriod = TimePeriod(rawValue: self.timePeriodControl.selectedSegmentIndex) else {
            return
        }
        
        forecastCellFactory.setTimePeriod(timePeriod: timePeriod)
        self.tableView.reloadData()
    }
    
    @objc private func handleCityButton() {
        print("Handle city button")
    }
    
    @objc private func handleNotificationButton() {
        print("Handle notification button")
    }
}

//MARK:- Prepare
private extension ForecastViewController {
    func prepareViewController() {
        view.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
        
        localizationObserver = NotificationCenter.default.addObserver(forName: .localizationChange, object: nil, queue: .main, using: { _ in
            self.tableView.reloadData()
        })
    }
    
    func prepareNavigationBar() {
        //City button
        cityButton.isHidden = true
        cityButton.addTarget(self, action: #selector(handleCityButton), for: .touchUpInside)
        let cityBarItem = UIBarButtonItem(customView: cityButton)
        
        let barSpacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
        barSpacer.width = 18
        
        //Notification button
        let notificationButton = UIButton()
        notificationButton.frame = .init(origin: .zero, size: .init(width: 40, height: 40))
        notificationButton.setImage(UIImage(named: "bell"), for: .normal)
        notificationButton.tintColor = ThemeManager.currentTheme.primaryTextColor
        notificationButton.addTarget(self, action: #selector(handleNotificationButton), for: .touchUpInside)
        
        let notificationBarButton = UIBarButtonItem(customView: notificationButton)
        notificationButton.contentEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 0)
        self.navigationItem.leftBarButtonItems = [barSpacer, cityBarItem]
        self.navigationItem.rightBarButtonItem = notificationBarButton
    }
    
    func prepareDayControlsView() {
        daysControlView.alpha = 0
        daysControlView.delegate = self
        view.addSubview(daysControlView)
        daysControlView.snp.makeConstraints { (make) in
            make.top.left.right.equalToSuperview()
        }
    }
    
    func prepareTableView() {
        forecastCellFactory.registerCells(on: tableView)
        tableView.contentInset = .init(top: 0, left: 0, bottom: 15, right: 0)
        tableView.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
        tableView.separatorStyle = .none
        tableView.tableFooterView = UIView()
        tableView.estimatedRowHeight = UITableView.automaticDimension
        tableView.rowHeight = UITableView.automaticDimension
        tableView.delegate = self
        tableView.dataSource = self
        view.addSubview(tableView)
        
        tableView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
    }
    
    func prepareTimePeriodControl() {
        let container = UIView()
        container.addSubview(self.timePeriodControl)
        timePeriodControl.selectedSegmentIndex = 0
        timePeriodControl.addTarget(self, action: #selector(handleSegmentDidChange), for: .valueChanged)
        
        self.timePeriodControl.snp.makeConstraints { (make) in
            make.left.right.equalToSuperview().inset(18).priority(.init(999))
            make.top.equalToSuperview().inset(30)
            make.bottom.equalToSuperview().priority(.init(999))
            make.height.equalTo(40).priority(.init(999))
        }
        
        tableView.tableHeaderView = container
    }
}

//MARK:- UITableView Delegate
extension ForecastViewController: UITableViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        guard
            let navVC = self.navigationController,
            viewModel.location?.daily.isEmpty == false,
            self.timePeriod == .daily
        else {
            return
        }
        
        if timePeriodCellFrame == .zero {
            timePeriodCellFrame = tableView.cellForRow(at: [0,0])?.frame ?? .zero
        }

        let startPointY = timePeriodCellFrame.origin.y + timePeriodCellFrame.height - self.daysControlView.frame.height
        
        if scrollView.contentOffset.y >= startPointY {
            if !navVC.isNavigationBarHidden {
                navVC.setNavigationBarHidden(true, animated: true)
                self.daysControlView.update(offset: self.viewModel.offsetHolder.currentOffset)
                UIView.animate(withDuration: 0.35) {
                    self.daysControlView.alpha = 1
                }
            }
        }
        else {
            if navVC.isNavigationBarHidden {
                navVC.setNavigationBarHidden(false, animated: true)
                UIView.animate(withDuration: 0.35) {
                    self.daysControlView.alpha = 0
                }
            }
        }
    }
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        forecastCellFactory.willDisplay(cell: cell)
    }
}

//MARK:- UITableView DataSource
extension ForecastViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return forecastCellFactory.numberOfRows(inSection: section)
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return forecastCellFactory.cellFromTableView(tableView: tableView,
                                                               indexPath: indexPath)
    }
}

//MARK:- ViewModel Delegate
extension ForecastViewController: ForecastViewModelDelegate {
    func viewModelDidChange<P>(model: P) where P : ViewModelProtocol {
        refreshCityButton()
        tableView.reloadData()
        refreshDayButtons()
    }
    
    func selectedWeatherDidChange() {
        switch timePeriod {
        case .daily:
            var indexPathToReload = [IndexPath]()
            for index in 0..<forecastCellFactory.numberOfRows(inSection: 0) {
                if index == 0 { continue }
                
                indexPathToReload.append([0, index])
            }
            
            tableView.reloadRows(at: indexPathToReload, with: .none)
            daysControlView.selectDayAt(index: viewModel.selectedDailyWeatherIndex)
        case .hourly:
            tableView.reloadData()
        }
    }
}

//MARK:- DaysControlView Delegate
extension ForecastViewController: DaysControlViewDelegate {
    func didSelectButtonAt(index: Int) {
        viewModel.selectDailyWeatherAt(index: index)
    }
    
    func offsetDidChange(offset: CGFloat) {
        viewModel.offsetHolder.update(offset: offset)
    }
}

//MARK:- TimePeriodOffset Delegate
extension ForecastViewController: TimePeriodOffsetDelegate {
    func offsetDidChange(newOffset: CGFloat) {
    }
}
