//
//  LKFScoringDetails.swift
//  LKF
//
//  Created by Alexander Holzer on 26.02.22.
//  Copyright © 2022 Alexander Holzer. All rights reserved.
//

import Foundation
@_implementationOnly import LibLKF

public class LKFScoringDetails {
    
    public let aufenthalt: LKFAufenthalt
    public let abt: [LKFScoringDetailsAbt]
    public let melGroups: [LKFScoringDetailsMEL]
    public let diagGroups: [LKFScoringDetailsDIAG]
    public let mainGroupIndex : Int
    public let isDiagGroup : Bool
    public let lineParts : [String]
    
    public let melGroupsWithNoAbt: [LKFScoringDetailsMEL]
    
    private var _mainGroup: LKFScoringDetailsGroup?
    
    public init? (aufenthalt: LKFAufenthalt) {
        self.aufenthalt = aufenthalt
        let lineBuffer = UnsafeMutablePointer<CChar>.allocate(capacity:1024)
        defer {
            lineBuffer.deallocate()
        }
        let aufenthaltPtr = aufenthalt.ptr
        
        guard LibLKF.lkf_scoringdetails_getHead(aufenthaltPtr, lineBuffer, 1024) > 0 else {
            return nil
        }

        lineParts = String.utf8String(cString: lineBuffer).components(separatedBy: "|")
        mainGroupIndex = Int(lineParts[0]) ?? 0
        isDiagGroup = (Int(lineParts[1]) ?? 0) != 0

        var melGroupArray = [LKFScoringDetailsMEL]()
        for i in 0..<aufenthalt.melCount {
            let melGroup = LKFScoringDetailsMEL(aufenthalt:aufenthalt, melIndex: i, mainGroupIndex: mainGroupIndex)
            if let sgi = melGroup.subgruppeIndex, sgi >= 0 {            
                melGroupArray.append(melGroup)
            }
        }
        self.melGroups = melGroupArray
        
        var abtArray = [LKFScoringDetailsAbt]()
        for i in 0..<aufenthalt.abtCount {
            LibLKF.lkf_scoringdetails_getAbt(aufenthaltPtr, i, lineBuffer, 1024)
        
            let mels = melGroupArray.filter { $0.mel.abtIndex != nil && $0.mel.abtIndex! == i }
            
            abtArray.append(LKFScoringDetailsAbt(aufenthalt:aufenthalt, abtIndex:i, mels: mels, line:String.utf8String(cString: lineBuffer)))
            melGroupArray.removeAll { $0.mel.abtIndex != nil && $0.mel.abtIndex! == i }
        }
        
        self.abt = abtArray
        self.melGroupsWithNoAbt = melGroupArray
    
        var diagGroupArray = [LKFScoringDetailsDIAG]()
        for i in 0..<aufenthalt.diagCount {
            let diagGroup = LKFScoringDetailsDIAG(aufenthalt:aufenthalt, diagIndex: i, mainGroupIndex: mainGroupIndex)
            if let sgi = diagGroup.subgruppeIndex, sgi >= 0 {
                diagGroupArray.append(diagGroup)
            }
        }
        self.diagGroups = diagGroupArray
        
        if isDiagGroup, let firstDiagGroup = diagGroupArray.first {
            var maxPkt = firstDiagGroup.SCGES ?? 0
            
            for d in 1..<diagGroupArray.count {
                guard let p = diagGroupArray[d].SCGES else {
                    continue
                }
                if p > maxPkt {
                    maxPkt = p
                }
            }
        }
    }
    
    public var groups : [LKFScoringDetailsGroup] {
        if isDiagGroup {
            return diagGroups
        }
        else {
            return melGroups
        }
    }
    
    public func group (groupIndex: Int32) -> LKFScoringDetailsGroup? {
        if isDiagGroup {
            for d in diagGroups {
                if let s = d.subgruppeIndex, s == groupIndex {
                    return d
                }
            }
        }
        else {
            for m in melGroups {
                if let s = m.subgruppeIndex, s == groupIndex {
                    return m
                }
            }
        }
        return nil
    }

    public func group (melIndex: UInt32) -> LKFScoringDetailsGroup? {
        for m in melGroups {
            if m.melIndex == melIndex {
                return m
            }
        }
        return nil
    }

    public func allAbts() -> [LKFScoringDetailsAbt] {
        var arr = [LKFScoringDetailsAbt]()
        arr.append(contentsOf: abt.filter({ a in
            return a.abt.ABTFC != "10000000"
        }))
        return arr
    }
    
    public var mainGroup : LKFScoringDetailsGroup {
        
        guard _mainGroup == nil else {
            return _mainGroup!
        }
        
        if isDiagGroup {
            for d in diagGroups {
                if d.mainGroup {
                    _mainGroup = d
                    break
                }
            }
        }
        else {
            for m in melGroups {
                if m.mainGroup {
                    _mainGroup = m
                    break
                }
            }
        }

        if (_mainGroup == nil) {
            _mainGroup = LKFScoringDetailsGroup(aufenthalt: aufenthalt, parts:["99"], mainGroupIndex: -1)
        }
        return _mainGroup!
    }
    
    public var traceLine : String {
        return "\(mainGroupIndex)\(isDiagGroup)"
    }
    
    public var comments : [String]? {
        return mainGroup.comments
    }
    
    public func createTrace() -> [String] {
        var arr = [String]()
        arr.append(traceLine)

        for a in abt {
            arr.append(a.traceLine)
        }

        for g in melGroups {
            arr.append(contentsOf: g.traceLines)
        }
        
        for g in diagGroups {
            arr.append(contentsOf: g.traceLines)
        }

        return arr
    }

}
