import Foundation

/// unit view model protocol
protocol JednotkaViewModelProtocol {
    var delegate: JednotkaViewModelDelegate? { get set }
    var detail: UnitDetailResult? { get }
    var parentDetail: UnitDetailResult { get }
    var contacts: [UnitContact] { get }
    var functions: [FunctionUnit] { get }
    var unitTree: [UnitTree] { get }
    var sections: [[NSObject]] { get }
    var loading: Bool { get }
    func refreshData()
    func isFirst() -> Bool
}

/// unit view model protocol delegate
protocol JednotkaViewModelDelegate: AnyObject {
    func didUpdate()
}

class PostalAddress: NSObject {
    var AddressType: String = ""
    var Value: String = ""
    
    init(type: String, value: String) {
        self.AddressType = type
        self.Value = value
    }
}

/// unit view model
class JednotkaViewModel: JednotkaViewModelProtocol {
    weak var delegate: JednotkaViewModelDelegate?
    var detail: UnitDetailResult?
    var parentDetail: UnitDetailResult = UnitDetailResult(completion: { _ in })
    var contacts: [UnitContact] = []
    var functions: [FunctionUnit] = []
    var unitTree: [UnitTree] = []
    var loading: Bool = true
    var sectionCount: Int = 0 {
        didSet {
            if sectionCount >= 4 {
                loading = false
                delegate?.didUpdate()
            }
        }
    }
    var sections: [[NSObject]] {
        let addres1 = Address(type: "Ulice", value: detail?.Street ?? "")
        let addres2 = Address(type: "Obec", value: "\(detail?.City ?? ""), \(detail?.Postcode ?? "")")
        let addresPostal1 = PostalAddress(type: "Ulice", value: detail?.PostalStreet ?? "")
        let addresPostal2 = PostalAddress(type: "Obec", value: "\(detail?.PostalCity ?? ""), \(detail?.PostalPostcode ?? "")")
        return [contacts, [addres1, addres2], [addresPostal1, addresPostal2], [parentDetail], functions, unitTree]
    }
    
    private var id: String
    private var first: Bool
    private var parentId: String = "" {
        didSet {
            guard let token = UserDefaults.userToken, parentId != "" else { return }
            getUnitDetail(token: token, id: parentId, parent: true)
        }
    }
    
    /// initialization function
    /// - Parameters:
    ///   - id: id for unit
    ///   - first: is this unit first
    init(id: String, first: Bool) {
        self.id = id
        self.first = first
    }
    
    /// function that returns true if unit is first
    /// - Returns: true if unit is first
    func isFirst() -> Bool {
        return first
    }
    
    
    /// function that refreshes data for view model if user has token
    func refreshData() {
        guard let token = UserDefaults.userToken else { return }
        loading = true
        getUnitDetail(token: token, id: id)
        getUnitContacts(token: token)
        getUnitFunctions(token: token)
        getUnitTree(token: token)
    }
    
    /// function that sets unit details for the view model
    /// - Parameters:
    ///   - token: token
    ///   - id: unit id
    ///   - parent: if parent exists
    private func getUnitDetail(token: String, id: String, parent: Bool = false) {
        let unit = UnitDetail(ID_Login: token, ID: id)
        let unitOutput = UnitDetailResult(completion: { [weak self] result in
            guard let res = result as? UnitDetailResult else { return }
            if parent {
                self?.parentDetail = res
            } else  {
                self?.detail = res
                self?.parentId = res.ID_UnitParent
            }
            self?.sectionCount+=1
        })
        API.shared.call(object: unit, result: unitOutput, serviceName: .organizationUnit)
    }
    
    /// function that sets the unit functions for the view model
    /// - Parameter token: token
    private func getUnitFunctions(token: String) {
        let unit = FunctionAll(ID_Login: token, ID_Unit: id)
        let unitOutput = FunctionAllResult(completion: { [weak self] result in
            guard let res = result as? FunctionAllResult else { return }
            self?.functions = self?.filterFunctions(functions: res.FunctionAllOutput) ?? []
            self?.sectionCount+=1
        })
        API.shared.call(object: unit, result: unitOutput, serviceName: .organizationUnit)
    }
    
    
    /// function that filters ony allowed types
    /// - Parameter functions: functions
    /// - Returns: filtered functions based on function type
    private func filterFunctions(functions: [FunctionUnit]) -> [FunctionUnit] {
        return functions.filter({ allowedFunctionTypes.contains(Int($0.ID_FunctionType) ?? 0) })
    }
    
    /// function that filters contacts based on publish status
    /// - Parameter contacts: contacts
    /// - Returns: contacts that can be published
    private func filterContacts(contacts: [UnitContact]) -> [UnitContact] {
        return contacts.filter({ $0.Publish == "true" })
    }
    
    /// function that sets the unit tree for the view model
    /// - Parameter token: token
    private func getUnitTree(token: String) {
        let unit = UnitTreeAll(ID_Login: token, ID_UnitParent: id)
        let unitOutput = UnitTreeAllResult(completion: { [weak self] result in
            guard let res = result as? UnitTreeAllResult else { return }
            self?.unitTree = res.UnitTreeAllOutput
            self?.sectionCount+=1
        })
        API.shared.call(object: unit, result: unitOutput, serviceName: .organizationUnit)
    }
    
    /// function that sets the unit contacts for the view model
    /// - Parameter token: token
    private func getUnitContacts(token: String) {
        let unit = UnitContactAll(ID_Login: token, ID_Unit: id)
        let unitOutput = UnitContactAllResult(completion: { [weak self] result in
            guard let res = result as? UnitContactAllResult else { return }
            self?.contacts = self?.filterContacts(contacts: res.UnitContactAllOutput) ?? []
            self?.sectionCount+=1
        })
        API.shared.call(object: unit, result: unitOutput, serviceName: .organizationUnit)
    }
    
}
