import UIKit
import Charts

/// registration view model protocol
protocol RegistraceViewModelProtocol {
    var delegate: RegistraceViewModelDelegate? { get set }
    var loading: Bool { get }
    var podrizeneJednotky: [Unit] { get }
    var registrovaneCleny: [MemberAge] { get }
    var vychovneStruktury: [DisplayMembers] { get }
    var vekoveStruktury: [DisplayMembers] { get }
    var years: [UnitRegistration] { get }
    var currentYear: UnitRegistration { get set }
    func refreshData()
    func getRegistations(for year: UnitRegistration)
    func getEntriesForJedontky() -> [PieChartDataEntry]
    func getEntriesForRegistrovaneCleny() -> [PieChartDataEntry]
    func getEntriesForVychovneStruktury() -> [PieChartDataEntry]
    func getEntriesForVekoveStruktury() -> [PieChartDataEntry]
}

/// registration view model delegate
protocol RegistraceViewModelDelegate: AnyObject {
    func didUpdate()
}

struct MemberItems {
    var members: Int
    var fHmembers: Int
}

struct DisplayMembers {
    var displayName: String
    var items: MemberItems
}

/// registration view model
class RegistraceViewModel: RegistraceViewModelProtocol {
    weak var delegate: RegistraceViewModelDelegate?
    var loading: Bool = true
    var years: [UnitRegistration] = []
    var podrizeneJednotky: [Unit] {
        units
    }
    
    /// function that returns entries for unit for given year
    /// - Returns: unit data entries for given year
    func getEntriesForJedontky() -> [PieChartDataEntry] {
        units.map { x in PieChartDataEntry(value: Double(x.Count) ?? 0, label: x.UnitType) }
    }
    
    /// computational variable that computes registration members
    var registrovaneCleny: [MemberAge] {
        guard membersAge.count > 0 else { return [] }
        let sumMembers = membersAge.reduce(0, { prev, curr  in
            if (["RadneCasopis", "Radne", "Cestne", "HostovaniCizi"].contains(curr.Row)) {
                return  prev + (Int(curr.Count) ?? 0)
            }
            return prev
        })
        let sumfMembers = membersAge.reduce(0, { prev, curr  in
            if (["RadneCasopis", "Radne", "Cestne"].contains(curr.Row)) {
                return  prev + (Int(curr.Count) ?? 0)
            }
            return prev
        })
        let sumMembersCat = MemberAge()
        sumMembersCat.DisplayName = "Členu této jednotky"
        sumMembersCat.Count = "\(sumMembers)"
        let sumfMembersCat = MemberAge()
        sumfMembersCat.DisplayName = "Řádnych a česntých členu"
        sumfMembersCat.Count = "\(sumfMembers)"
        return [sumMembersCat, sumfMembersCat]
    }
    
    /// function that returns entries for regirstation for given year
    /// - Returns: registration data entries for given year
    func getEntriesForRegistrovaneCleny() -> [PieChartDataEntry] {
        var data: [PieChartDataEntry] = []
        data.append(PieChartDataEntry(value: Double(registrovaneCleny[0].Count) ?? 0, label: registrovaneCleny[0].DisplayName))
        data.append(PieChartDataEntry(value: Double(registrovaneCleny[1].Count) ?? 0, label: registrovaneCleny[1].DisplayName))
        return data
    }
    
    /// computational variable that computes member functions structures
    var vychovneStruktury: [DisplayMembers] {
        var dict = Dictionary<String, MemberItems>()
        membersCategory.forEach({
            var mem = dict[$0.MembershipCategory]?.members ?? 0
            var fHmem = dict[$0.MembershipCategory]?.fHmembers ?? 0
            if (["RadneCasopis", "Radne", "Cestne", "HostovaniCizi"].contains($0.Row)) {
                mem = mem + (Int($0.Count) ?? 0)
            }
            if (["RadneCasopis", "Radne", "Cestne"].contains($0.Row)) {
                fHmem = fHmem + (Int($0.Count) ?? 0)
            }
            dict[$0.MembershipCategory] = MemberItems(members: mem, fHmembers: fHmem)
        })
        let result = dict.map({ DisplayMembers(displayName: $0.key, items: $0.value) }).sorted{ $0.displayName > $1.displayName }
        return result
    }
    
    /// function that returns entries for member functions for given year
    /// - Returns: member functions data entries for given year
    func getEntriesForVychovneStruktury() -> [PieChartDataEntry] {
        vychovneStruktury.map { x in PieChartDataEntry(value: Double(x.items.fHmembers + x.items.members), label: x.displayName) }
    }
    
    /// computational variable that computes member ages structures
    var vekoveStruktury: [DisplayMembers] {
        var dict = Dictionary<String, MemberItems>()
         membersAge.forEach({
             var mem = dict[$0.AgeCategory]?.members ?? 0
             var fHmem = dict[$0.AgeCategory]?.fHmembers ?? 0
             if (["RadneCasopis", "Radne", "Cestne", "HostovaniCizi"].contains($0.Row)) {
                 mem = mem + (Int($0.Count) ?? 0)
             }
             if (["RadneCasopis", "Radne", "Cestne"].contains($0.Row)) {
                 fHmem = fHmem + (Int($0.Count) ?? 0)
             }
             dict[$0.AgeCategory] = MemberItems(members: mem, fHmembers: fHmem)
         })
         let result = dict.map({ DisplayMembers(displayName: $0.key, items: $0.value) }).sorted{ $0.displayName > $1.displayName }
         return result
    }
    
    /// function that returns entries for member ages for given year
    /// - Returns: member ages data entries for given year
    func getEntriesForVekoveStruktury() -> [PieChartDataEntry] {
        vekoveStruktury.map { x in PieChartDataEntry(value: Double(x.items.fHmembers + x.items.members), label: x.displayName) }
    }
    
    private var units: [Unit] = []
    private var membersAge: [MemberAge] = []
    private var membersCategory: [MemberCategory] = []
    var currentYear: UnitRegistration = UnitRegistration() {
        didSet {
            if oldValue != currentYear {
                delegate?.didUpdate()
            }
        }
    }
    private var id: String
    
    /// initialization function
    /// - Parameter id: unit id
    init(id: String) {
        self.id = id
    }
    
    /// function that refreshes and sets the view model data for year
    func refreshData() {
        guard let token = UserDefaults.userToken else { return }
        let unit = UnitRegistrationAll(ID_Login: token, ID_Unit: id)
        let output = UnitRegistrationAllResult(completion: { [weak self] result in
            guard let res = result as? UnitRegistrationAllResult else { return }
            guard let year = res.UnitRegistrationAllOutput.first else { return }
            self?.years = res.UnitRegistrationAllOutput
            self?.currentYear = year
            self?.getRegistations(for: year)
        })
        API.shared.call(object: unit, result: output, serviceName: .organizationUnit)
    }
    
    
    /// function that refreshets and sets view model data for registration for given year
    /// - Parameter year: tear
    func getRegistations(for year: UnitRegistration) {
        guard let token = UserDefaults.userToken else { return }
        loading = true
        delegate?.didUpdate()
        let unit = UnitRegistrationMembers(ID_Login: token, ID: year.ID)
        let output = UnitRegistrationMembersResult(completion: { [weak self] result in
            self?.units = result.Units
            self?.membersAge = result.MembersAge
            self?.membersCategory = result.MembersCategory
            self?.loading = false
            self?.delegate?.didUpdate()
        })
        API.shared.call(object: unit, result: output, serviceName: .organizationUnit)
    }
    
}
