//
//  LKFContextErrors.swift
//  LKF
//
//  Created by Alexander Holzer on 16.12.23.
//  Copyright © 2023 Alexander Holzer. All rights reserved.
//

import Foundation

public class LKFContextErrors {
    
    public private(set) var errorPerType = [String:[String:[String]]]()
    
    func add (code: String, key: String, line: String) {
        if errorPerType[code] != nil {
            if errorPerType[code]![key] != nil {
                errorPerType[code]![key]!.append(line)
            }
            else {
                errorPerType[code]![key] = [line]
            }
        }
        else {
            errorPerType[code] = [key:[line]]
        }
    }
    
    init (context: LKFContext) {
        
        let errors = context.getErrors(fields: [.code, .satzart, .aufnr, .ident, .feld_lang, .text])
        
        for e in errors {
            let parts = e.split(separator: ";")
            
            guard parts.count > 2 else {
                continue
            }
            
            let code = String(parts[0].trimmingCharacters(in: .whitespacesAndNewlines))
            let key : String
            
            let trimmmedAufNr = String(parts[2].trimmingCharacters(in: .whitespacesAndNewlines))
            let trimmedIdent = String(parts[3].trimmingCharacters(in: .whitespacesAndNewlines))
            let trimmedValue = String(parts[4].trimmingCharacters(in: .whitespacesAndNewlines))
            
            if trimmmedAufNr.count > 0 {
                key = trimmmedAufNr
            }
            else if trimmedIdent.count > 0 {
                key = trimmedIdent
            }
            else {
                key = trimmedValue
            }
            
            add(code: code, key: key, line: e)
        }
    }
    
    public func compare(source: LKFContextErrors, sourceName: String = "source", targetName: String = "target", ignore:Set<String>? = nil) -> [String]? {
        
        
        
        var arr = [String]()
        for ept in errorPerType {
            if let ignore, ignore.contains(ept.key) {
                continue
            }
            guard let sc = source.errorPerType[ept.key] else {
                if ept.value.count == 1, let firstKey = ept.value.first {
                    if firstKey.value.count == 1, let firstError = firstKey.value.first {
                        arr.append ("\(ept.key) only in \(targetName): \(firstError)")
                    }
                    else {
                        arr.append ("\(ept.key) only in \(targetName): \(firstKey.key) with \(firstKey.value.count) occurrences")
                    }
                }
                else {
                    arr.append ("\(ept.key) only in \(targetName): \(ept.value.count) keys")
                }
                continue
            }
            
            for epc in ept.value {
                guard let spc = sc[epc.key] else {
                    if epc.value.count == 1, let first = epc.value.first {
                        arr.append ("\(ept.key).\(epc.key) only in \(targetName): \(first)")
                    }
                    else {
                        arr.append ("\(ept.key).\(epc.key) only in \(targetName): \(epc.value.count) occurrences")
                    }
                    
                    continue
                }
                if spc.count != epc.value.count {
                    arr.append ("\(ept.key).\(epc.key) different count (\(sourceName)=\(spc.count), \(targetName)=\(epc.value.count)")
                }
            }
            for spc in sc {
                if ept.value[spc.key] == nil {
                    if spc.value.count == 1, let first = spc.value.first {
                        arr.append ("\(ept.key).\(spc.key) only in \(sourceName): \(first)")
                    }
                    else {
                        arr.append ("\(ept.key).\(spc.key) only in \(sourceName): \(spc.value.count) occurrences")
                    }
                    continue
                }
            }
        }
        for ept in source.errorPerType {
            if let ignore, ignore.contains(ept.key) {
                continue
            }
            if errorPerType[ept.key] == nil {
                if ept.value.count == 1, let first = ept.value.first {
                    arr.append ("\(ept.key).\(ept.key) only in \(sourceName): \(first)")
                }
                else {
                    arr.append ("\(ept.key) only on \(sourceName): \(ept.value.count) occurrences")
                }
            }
        }
        return arr.count > 0 ? arr : nil
    }
}

