import UIKit
import Eureka
import RxSwift

enum AddedBy: String, CustomStringConvertible, CaseIterable {
    case anyone
    case me
    case anyoneButMe
    
    var description: String {
        switch self {
        case .anyone: return NSLocalizedString("Anyone", comment: "Added by")
        case .me: return NSLocalizedString("Me", comment: "Added by")
        case .anyoneButMe: return NSLocalizedString("Anyone but me", comment: "Added by")
        }
    }
}

enum SortParameter: String, CustomStringConvertible, CaseIterable {
    case addedDate
    case updatedDate
    
    var description: String {
        switch self {
        case .addedDate: return NSLocalizedString("added time", comment: "sort by added time")
        case .updatedDate: return NSLocalizedString("updated time", comment: "sort by updated time")
        }
    }
}

enum SortOrder: String, CustomStringConvertible, CaseIterable {
    case ascending
    case descending
    
    var description: String {
        switch self {
        case .ascending: return NSLocalizedString("ascending", comment: "sort order")
        case .descending: return NSLocalizedString("descending", comment: "sort order")
        }
    }
}

class FiltersController: FormViewController {
    
    var done = false
    var filter: Filter!
    var onDone: (() -> Void)?
    var regions: [VehicleRegion] = []
    
    let bag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        form +++ Section(NSLocalizedString("Main filters", comment: "")) { $0.tag = "MainFilters" }
            <<< PushRow<String>("Brand") { row in
                row.title = NSLocalizedString("Brand", comment: "")
                row.value = self.filter.brand ?? "Any"
                row.selectorTitle = NSLocalizedString("Brands", comment: "")
                row.optionsProvider = .lazy({ form, completion in
                    Api.getBrands().observeOn(MainScheduler.instance).subscribe(onSuccess: { brands in
                        completion(["Any"] + brands)
                    }, onError: { error in
                        print("Get brands error: ", error)
                    }).disposed(by: self.bag)
                })
            }.onPresent(removeSectionName(from:to:))
            .onChange { self.filter.brand = $0.value == "Any" ? nil : $0.value }
            .cellUpdate { $1.value = self.filter.brand ?? "Any" }
            
            <<< PushRow<String>("Model") { row in
                row.title = NSLocalizedString("Model", comment: "")
                row.value = self.filter.model ?? "Any"
                row.disabled = "$Brand == 'Any'"
                row.optionsProvider = .lazy({ form, completion in
                    guard let brand = self.filter.brand else {
                        completion(["Any"])
                        return
                    }
                    Api.getModels(of: brand).observeOn(MainScheduler.instance).subscribe(onSuccess: { models in
                        completion(["Any"] + models)
                    }, onError: { error in
                        print("Get models error: ", error)
                    }).disposed(by: self.bag)
                })
            }.onPresent(removeSectionName(from:to:))
            .onChange { self.filter.model = $0.value == "Any" ? nil : $0.value }
            .cellUpdate { $1.value = self.filter.model ?? "Any" }
            
            <<< PushRow<String>("Color") { row in
                row.title = NSLocalizedString("Color", comment: "")
                row.value = self.filter.color ?? "Any"
                row.optionsProvider = .lazy({ form, completion in
                    Api.getColors().observeOn(MainScheduler.instance).subscribe(onSuccess: { colors in
                        completion(["Any"] + colors)
                    }, onError: { error in
                        print("Get colors error: ", error)
                    }).disposed(by: self.bag)
                })
            }.onPresent(removeSectionName(from:to:))
            .onChange { self.filter.color = $0.value == "Any" ? nil : $0.value }
            .cellUpdate { $1.value = self.filter.color ?? "Any" }
        
            <<< PushRow<String>("Year") { row in
                row.title = NSLocalizedString("Year", comment: "Manufacturing year")
                row.value = self.filter.year ?? "Any"
                row.optionsProvider = .lazy({ form, completion in
                    Api.getYears().observeOn(MainScheduler.instance).subscribe { years in
                        completion(["Any"] + years.map(String.init))
                    } onError: { error in
                        print("Get years error: \(error)")
                    }.disposed(by: self.bag)
                })
            }
            .onChange { self.filter.year = $0.value == "Any" ? nil : $0.value }
            .cellUpdate { $1.value = self.filter.year ?? "Any" }
        
        form +++ Section() { $0.tag = "Regions" }
            <<< LabelRow("RegionsRow") { row in
                row.title = NSLocalizedString("Regions", comment: "")
                row.value = self.filter.regions?.map(String.init).joined(separator: ",") ?? "Any"
                row.cellUpdate { cell, _ in
                    cell.accessoryType = .disclosureIndicator
                    row.value = self.filter.regions?.map(String.init).joined(separator: ",") ?? "Any"
                }
            }
            .onCellSelection { cell, row in
                let sb = UIStoryboard(name: "Main", bundle: nil)
                let vc = sb.instantiateViewController(identifier: "RegionsController") as RegionsController
                vc.regionCodes = self.filter.regions ?? []
                vc.onDone = { regions in
                    row.value = regions?.map(String.init).joined(separator: ",") ?? "Any"
                    self.filter.regions = regions
                }
                self.navigationController?.pushViewController(vc, animated: true)
            }
        
        form +++ Section() { $0.tag = "AddedByMe" }
            <<< ActionSheetRow<String>("AddedByMeRow") { row in
                row.title = NSLocalizedString("Added by", comment: "")
                row.selectorTitle = NSLocalizedString("Added by", comment: "")
                row.options = AddedBy.allCases.map { $0.description }
                row.value = self.filter.addedBy?.description ?? AddedBy.anyone.description
            }
            .onChange { row in
                if let index = row.options?.firstIndex(of: row.value ?? "") {
                    self.filter.addedBy = AddedBy.allCases[index]
                } else {
                    self.filter.addedBy = .anyone
                }
            }
            .cellUpdate { cell, row in
                row.value = self.filter.addedBy?.description ?? AddedBy.anyone.description
            }
        
        form +++ Section(NSLocalizedString("Update time", comment: ""))
            <<< DateInlineRow("FromDateUpdated") { row in
                row.title = NSLocalizedString("From", comment: "")
                row.noValueDisplayText = NSLocalizedString("Beginning", comment: "")
                row.value = self.filter.fromDateUpdated
            }
            .onChange { self.filter.fromDateUpdated = $0.value }
            .cellUpdate(self.update(cell:row:))
            <<< DateInlineRow("ToDateUpdated") { row in
                row.title = NSLocalizedString("To", comment: "")
                row.noValueDisplayText = NSLocalizedString("Now", comment: "")
                row.value = self.filter.toDateUpdated
            }
            .onChange { self.filter.toDateUpdated = $0.value }
            .cellUpdate(self.update(cell:row:))
        
        form +++ Section(NSLocalizedString("Added time", comment: ""))
            <<< DateInlineRow("FromDate") { row in
                row.title = NSLocalizedString("From", comment: "")
                row.noValueDisplayText = NSLocalizedString("Beginning", comment: "")
                row.value = self.filter.fromDate
            }
            .onChange { self.filter.fromDate = $0.value }
            .cellUpdate(self.update(cell:row:))
            <<< DateInlineRow("ToDate") { row in
                row.title = NSLocalizedString("To", comment: "")
                row.noValueDisplayText = NSLocalizedString("Now", comment: "")
                row.value = self.filter.toDate
            }
            .onChange { self.filter.toDate = $0.value }
            .cellUpdate(self.update(cell:row:))
        
        form +++ Section(NSLocalizedString("Sort", comment: "Header section. Noun."))
            <<< PickerInlineRow<SortParameter>("SortBy") { row in
                row.title = NSLocalizedString("Sort by", comment: "")
                row.value = self.filter.sortBy
                row.options = SortParameter.allCases
            }
            .onChange { self.filter.sortBy = $0.value }
            .cellUpdate { $1.value = self.filter.sortBy }
            <<< SegmentedRow<SortOrder>("SortOrder") { row in
                row.title = NSLocalizedString("Order", comment: "sort order")
                row.value = self.filter.sortOrder
                row.options = SortOrder.allCases
            }
            .onChange { self.filter.sortOrder = $0.value }
            .cellUpdate { $1.value = self.filter.sortOrder }
        
        form +++ Section()
            <<< ButtonRow("ClearAll") { $0.title = NSLocalizedString("Clear all filters", comment: "") }.onCellSelection { cell, row in
                self.filter.clear()
                for section in self.form.allSections {
                    // For some reason certain cells do not redraw after first reload
                    section.reload()
                    section.reload()
                }
            }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.done = false
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if self.done {
            self.onDone?()
        }
    }
    
    @IBAction func onDone(_ sender: UIBarButtonItem) {
        self.done = true
        self.navigationController?.popViewController(animated: true)
    }
    
    func removeSectionName(from: FormViewController, to: SelectorViewController<SelectorRow<PushSelectorCell<String>>>) {
        to.sectionKeyForValue = { _ in "" }
    }
    
    func update(cell: DateInlineRow.Cell, row: DateInlineRow) {
        guard let tag = row.tag else { return }
        
        let date = self.date(from: tag)
        if date != nil {
            let button = UIButton(type: .close)
            button.accessibilityLabel = row.tag
            button.addTarget(self, action: #selector(self.clearDate(_:)), for: .touchUpInside)
            button.sizeToFit()
            cell.accessoryView = button
        } else {
            cell.accessoryView = nil
        }
        row.value = date
    }
    
    func date(from tag: String) -> Date? {
        switch tag {
        case "FromDate": return self.filter.fromDate
        case "ToDate": return self.filter.toDate
        case "FromDateUpdated": return self.filter.fromDateUpdated
        case "ToDateUpdated": return self.filter.toDateUpdated
        default: return nil
        }
    }
    
    @objc func clearDate(_ sender: UIButton) {
        guard let tag = sender.accessibilityLabel else { return }
        guard let row = self.form.rowBy(tag: tag) as? DateInlineRow else { return }
        
        if tag == "FromDate" {
            self.filter.fromDate = nil
        } else {
            self.filter.toDate = nil
        }
        
        row.value = nil
        row.baseCell.accessoryView = nil
        row.baseCell.update()
    }
}
