import Foundation
import UIKit

/// person view model protocol
protocol OsobaViewModelProtocol {
    var delegate: OsobaViewModelDelegate? { get set }
    var loading: Bool { get }
    var contacts: [Contact] { get }
    var qualifications: [Qualification] { get }
    var functions: [Function] { get }
    var memberships: [Membership] { get }
    var offers: [Offer] { get }
    var detail: PersonDetailResult? { get }
    var sections: [[NSObject]] { get }
    func reloadData()
    func getMainPhone() -> String?
    func getPhone(item: Contact) -> String
    func getPhoto() -> UIImage?
}

/// preson view model delegate protocol
protocol OsobaViewModelDelegate: AnyObject {
    func didUpdate()
}

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

/// person view model
class OsobaViewModel: OsobaViewModelProtocol {
    weak var delegate: OsobaViewModelDelegate?
    var loading: Bool = true
    var contacts: [Contact] = []
    var qualifications: [Qualification] = []
    var functions: [Function] = []
    var memberships: [Membership] = []
    var offers: [Offer] = []
    var detail: PersonDetailResult?
    var sections: [[NSObject]] {
        let addres1 = Address(type: "Ulice", value: detail?.Street ?? "")
        let addres2 = Address(type: "Obec", value: "\(detail?.City ?? ""), \(detail?.Postcode ?? "")")
        var data: [[NSObject]] = [[addres1, addres2]]
        [contacts, qualifications, functions, memberships, offers].forEach({ x in
            if (x as? Array<Any>)?.count ?? 0 > 0 {
                data.append(x as! [NSObject])
            }
        })
        return data
    }
    
    private var photo: String = ""
    private var id: String
    
    init(id: String) {
        self.id = id
    }
    
    /// function that return main phone for person
    /// - Returns: main phone number
    func getMainPhone() -> String? {
        let phone = contacts.filter({ $0.ContactType.contains("Telefon") || $0.ContactType.contains("Mobil") })
        guard let phoneString = phone.first?.Value else { return nil }
        return "+421 \(phoneString)"
    }
    
    /// function that returns phone number based on contact
    /// - Parameter item: contact
    /// - Returns: phone number
    func getPhone(item: Contact) -> String {
        if (item.ContactType.contains("Telefon") || item.ContactType.contains("Mobil")) {
            return "+421 \(item.Value)"
        }
        return item.Value
    }
    
    /// function that returns photo
    /// - Returns: photo as UIImage
    func getPhoto() -> UIImage? {
        guard let data = Data(base64Encoded: photo) else { return nil }
        return UIImage(data: data)
    }
    
    /// reloads view model data if user has token
    func reloadData() {
        guard let token = UserDefaults.userToken else { return }
        getContacts(token: token)
        getPersonDetail(token: token)
        getContacts(token: token)
        getPersonQualifications(token: token)
        getPersonOffers(token: token)
        getPersonMemberships(token: token)
        getPersonFunctions(token: token)
        getPersonPhoto(token: token)
    }
    
    /// function that sets contact data
    /// - Parameter token: token
    private func getContacts(token: String) {
        let person = PersonContactAll(ID_Login: token, ID_Person: id)
        let output = PersonContactAllResult(completion: { [weak self] result in
            guard let res = result as? PersonContactAllResult else { return }
            self?.contacts = self?.filterContacts(contacts: res.PersonContactAllOutput) ?? []
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: person, result: output, serviceName: .organizationUnit)
    }
    
    /// function that filders contacts that are main
    /// - Parameter contacts: contacts
    /// - Returns: contacts that are main
    private func filterContacts(contacts: [Contact]) -> [Contact] {
        return contacts.filter({ $0.IsMain == "true" })
    }
    
    /// function that sets person detail data
    /// - Parameter token: token
    private func getPersonDetail(token: String) {
        let person = PersonDetail(ID_Login: token, ID: id)
        let output = PersonDetailResult(completion: { [weak self] result in
            guard let res = result as? PersonDetailResult else { return }
            self?.detail = res
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: person, result: output, serviceName: .organizationUnit)
    }
    
    /// function that sets person qualifications data
    /// - Parameter token: token
    private func getPersonQualifications(token: String) {
        let person = QualificationAll(ID_Login: token, ID_Person: id)
        let output = QualificationAllResult(completion: { [weak self] result in
            guard let res = result as? QualificationAllResult else { return }
            self?.qualifications = res.QualificationAllOutput
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: person, result: output, serviceName: .organizationUnit)
    }
    
    /// function that sets person functions data
    /// - Parameter token: token
    private func getPersonFunctions(token: String) {
        let person = FunctionAllPerson(ID_Login: token, ID_Person: id)
        let output = FunctionAllPersonResult(completion: { [weak self] result in
            guard let res = result as? FunctionAllPersonResult else { return }
            self?.functions = res.FunctionAllOutput
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: person, result: output, serviceName: .organizationUnit)
    }
    
    /// function that sets person membership data
    /// - Parameter token: token
    private func getPersonMemberships(token: String) {
        let person = MembershipAllPerson(ID_Login: token, ID_Person: id)
        let output = MembershipAllPersonResult(completion: { [weak self] result in
            guard let res = result as? MembershipAllPersonResult else { return }
            self?.memberships = res.MembershipAllOutput
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: person, result: output, serviceName: .organizationUnit)
    }
    
    /// function that sets person offers data
    /// - Parameter token: token
    private func getPersonOffers(token: String) {
        let person = OfferAll(ID_Login: token, ID_Person: id)
        let output = OfferAllResult(completion: { [weak self] result in
            guard let res = result as? OfferAllResult else { return }
            self?.offers = res.OfferAllOutput
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: person, result: output, serviceName: .organizationUnit)
    }
    
    /// function that sets person photo data
    /// - Parameter token: token
    private func getPersonPhoto(token: String) {
        let person = PersonPhoto(ID_Login: token, ID: id, Size: "normal")
        let output = PersonPhotoResult(completion: { [weak self] result in
            guard let res = result as? PersonPhotoResult else { return }
            self?.photo = res.PhotoContent
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: person, result: output, serviceName: .organizationUnit)
    }
    
}
