//
//  lkf2022Tests.swift
//  lkfcTests
//
//  Created by Alexander Holzer on 21.06.21.
//  Copyright © 2021 Alexander Holzer. All rights reserved.
//

import XCTest
@testable import lkfc

class lkf2022Tests: XCTestCase {
    
    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func createContextWith (model: UInt32, lines : [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith(model:model, lines:lines)
    }
    
    func combine (_ first:[String], _ second:[String]) -> [String] {
        return lkfcTests.combine(first, second)
    }


    static var fall_HX04 =
        [
            "X01|K901|123||20190109|0615|I|20030603|25|W|AT|AT|8753|62007|1|P||||8|20190109|1800|15|J|2",
            "X02|K901|123||20190109|001|16628500|20190109|0615|J|20190109|1800||||N|25|",
            "X03|K901|123||20190109|C15.1|H|D||",
            "X04|K901|123||20190109|HZ010||J|1|20190109|0740||K914|"
        ]

    func testHX04() throws {
        var context = try createContextWith(model:2021, lines: lkf2022Tests.fall_HX04)
        _ = lkfcTests.resultForContext(context: context)
        var errors = context.errorsWith (code:"HX04") // Diagnosen-Kombination
        XCTAssert (errors != nil, "missing warning HX04")

        context = try createContextWith(model:2022, lines: lkf2022Tests.fall_HX04)
        _ = lkfcTests.resultForContext(context: context)
        errors = context.errorsWith (code:"HX04") // Diagnosen-Kombination
        XCTAssert (errors == nil, "HX04 not expected")
    }
    
    /*
    func testUnloadMetadata() {
        var context = try createContextWith(model:2021, lines: lkf2022Tests.fall_HX04)
        try context.execute() // ok
        LKFGlobal.current.unloadMetaData()
        context = try createContextWith(model:2021, lines: lkf2022Tests.fall_HX04)
        try context.execute() // ok
        context = try createContextWith(model:2021, lines: lkf2022Tests.fall_HX04)
        LKFGlobal.current.unloadMetaData()
        try context.execute() // crash
    }
    */
    static var fallAM110 =
        [
            "X01|K901|123||20210109|0615|I|20030603|25|W|AT|AT|8753|62007|1|P||||8|20210109|1800|15|J|2",
            "X02|K901|123||20210109|001|16516802|20210109|0615|J|20210109|1800||||N|25|",
            "X03|K901|123||20210109|M48.0|H|D||",
            "X04|K901|123||20210109|AM110||J|1|20210109|0740|16516802||"
        ]

    static var fallAM100 =
    [
        "X01|K901|123||20210109|0615|S|20030603|25|W|AT|AT|8753|62007|A|P||||S|20210113|1800|15|J|2",
        "X02|K901|123||20210109|001|14516801|20210109|0615||20210113|1800||||N|25|",
        "X03|K901|123||20210109|M48.0|H|D||",
        "X04|K901|123||20210109|AM100||J|1|20210111|0740|14516801||"
    ]

    
    static var fallAM100_2021 = [
        "L01|2021|K901|16516802|O|TK|",
        "L01|2021|K901|14516801|O|02|",
    ]

    static var fallAM100_2022 = [
        "L01|2021|K901|16516802|O|ET|",
        "L01|2021|K901|14516801|O|ES|",
    ]
    
    static var fallAM150 =
        [
            "X01|K901|123||20210109|0615|I|20030603|25|W|AT|AT|8753|62007|1|P||||8|20210109|1800|15|J|2",
            "X02|K901|123||20210109|001|16516803|20210109|0615|J|20210109|1800||||N|25|",
            "X03|K901|123||20210109|M48.0|H|D||",
            "X04|K901|123||20210109|AM150||J|1|20210109|0740|16516803||",
            "L01|2021|K901|16516803|O|KT|",
            "L01|2021|K901|14516803|O|KS|"
        ]

    static var fallAM140 =
    [
        "X01|K901|123||20210109|0615|S|20030603|25|W|AT|AT|8753|62007|A|P||||S|20210113|1800|15|J|2",
        "X02|K901|123||20210109|001|14516803|20210109|0615||20210113|1800||||N|25|",
        "X03|K901|123||20210109|M48.0|H|D||",
        "X04|K901|123||20210109|AM140||J|1|20210111|0740|14516803||",
        "L01|2021|K901|16516803|O|KT|",
        "L01|2021|K901|14516803|O|KS|"
    ]

    static var fallAM150falsch =
        [
            "X01|K901|123||20210109|0615|I|20030603|25|W|AT|AT|8753|62007|1|P||||8|20210109|1800|15|J|2",
            "X02|K901|123||20210109|001|16526803|20210109|0615|J|20210109|1800||||N|25|",
            "X03|K901|123||20210109|M48.0|H|D||",
            "X04|K901|123||20210109|AM150||J|1|20210109|0740|16526803||",
            "L01|2021|K901|16526803|O|KT|",
            "L01|2021|K901|14526803|O|KS|"
        ]

    static var fallAM140falsch =
    [
        "X01|K901|123||20210109|0615|S|20030603|25|W|AT|AT|8753|62007|A|P||||S|20210113|1800|15|J|2",
        "X02|K901|123||20210109|001|14526803|20210109|0615||20210113|1800||||N|25|",
        "X03|K901|123||20210109|M48.0|H|D||",
        "X04|K901|123||20210109|AM140||J|1|20210111|0740|14526803||",
        "L01|2021|K901|16526803|O|KT|",
        "L01|2021|K901|14526803|O|KS|"
    ]


    
    func testAM100() throws {
        
        let am100_2021 = combine (lkf2022Tests.fallAM100, lkf2022Tests.fallAM100_2021)
        
        var context = try createContextWith(model:2021, lines: am100_2021)
        try context.execute()
        var result = context.getResultLine(forIndex: 0)
        XCTAssert(context.warningCount == 0, "no warnings expected")
        XCTAssert(result == "X05|K901|123||20210109|MEL32.01|A||||1163|||||1163", "result differs")
        
        let am110_2021 = combine (lkf2022Tests.fallAM110, lkf2022Tests.fallAM100_2021)
        
        context = try createContextWith(model:2021, lines: am110_2021)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(context.warningCount == 0, "no warnings expected")
        XCTAssert(result == "X05|K901|123||20210109|AMG20.12|A|204||||||||204", "result differs")

        context = try createContextWith(model:2022, lines: am100_2021)
        try context.execute()
        var errors = context.errorsWith (code:"WX3Q") // keine eingestufte Abteilung, weil 02 ungueltig
        XCTAssert (errors != nil, "missing warning WX3Q")

        context = try createContextWith(model:2022, lines: am110_2021)
        try context.execute()
        errors = context.errorsWith (code:"EX26") // keine eingestufte Abteilung, weil 02 ungueltig
        XCTAssert (errors != nil, "missing error EX26")

        let am100_2022 = combine (lkf2022Tests.fallAM100, lkf2022Tests.fallAM100_2022)
        let am110_2022 = combine (lkf2022Tests.fallAM110, lkf2022Tests.fallAM100_2022)
        context = try createContextWith(model:2022, lines: am100_2022)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(context.warningCount == 0, "no warnings expected")
        XCTAssert(result == "X05|K901|123||20210109|MEL32.01|A||||1163|||||1163", "result differs")

        context = try createContextWith(model:2022, lines: am110_2022)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(context.warningCount == 0, "no warnings expected")
        XCTAssert(result == "X05|K901|123||20210109|AMG20.12|A|204||||||||204", "result differs")

        context = try createContextWith(model:2022, lines: lkf2022Tests.fallAM150)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(context.warningCount == 0, "no warnings expected")
        XCTAssert(result == "X05|K901|123||20210109|AMG20.13|A|296||||||||296", "result differs")

        context = try createContextWith(model:2022, lines: lkf2022Tests.fallAM140)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(context.warningCount == 0, "no warnings expected")
        XCTAssert(result == "X05|K901|123||20210109|MEL32.03|A||||1684|||||1684", "result differs")
        
        context = try createContextWith(model:2022, lines: lkf2022Tests.fallAM150falsch)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        errors = context.errorsWith (code:"EX4B")
        XCTAssert (errors != nil, "missing error EX4B")

        context = try createContextWith(model:2022, lines: lkf2022Tests.fallAM140falsch)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        errors = context.errorsWith (code:"EX4B")
        XCTAssert (errors != nil, "missing error EX4B")

    }
    
    static var fallosg =
        [
    "X01|K640|123||20210101|0600|S|19311011|85|W|AT|AT|8605|62140|T|P||K638||E|20210312|1040|15|J|0||",
    "X02|K640|123||20210101|001|11111100|20210101|0600|||||||N|85|",
    "X02|K640|123||20210101|002|13113600|20210123|1000|||||||N|85|",
    "X03|K640|123||20210101|I70.2|H|||",
    "X03|K640|123||20210101|H35.3|Z|||",
    "X04|K640|123||20210101|BG030|L|J|1|20210122|1152||K638|"
    ];
    
    func testOSGFix () throws {
        let context = try createContextWith(model:2021, lines: lkf2022Tests.fallosg)
        context.flags = 8388608
        try context.execute()
        let errors = context.errorsWith (code:"WX2Q")
        //print(context.getErrorsAndWarnings())
        XCTAssert(errors == nil, "WX2Q not expected")
    }
    
    static var fallan100KA =
        [
    "X01|K640|123||20210101|0600|S|19311011|85|W|AT|AT|8605|62140|T|P||K638||E|20210312|1040|15|J|0||",
    "X02|K640|123||20210101|001|13118001|20210101|0600|||||||N|85|",
    "X02|K640|123||20210101|002|13113600|20210123|1000|||||||N|85|",
    "X03|K640|123||20210101|R06.3|H|||",
    "X04|K640|123||20210101|AN010||J|1|20210122|1152||K638|",
    "L01|2021|K638||M|XM"
    ];

    static var fallan110 =
        [
    "X01|K640|123||20210101|0600|S|19311011|85|W|AT|AT|8605|62140|T|P||K638||E|20210312|1040|15|J|0||",
    "X02|K640|123||20210101|001|13518001|20210101|0600|||||||N|85|",
    "X02|K640|123||20210101|002|13113600|20210123|1000|||||||N|85|",
    "X03|K640|123||20210101|G47.1|H|||",
    "X04|K640|123||20210101|AN011||J|1|20210122|1152|13518001||",
    "L01|2021|K640||M|XN"
    ];

    static var fallan100 =
        [
    "X01|K640|123||20210101|0600|S|19311011|85|W|AT|AT|8605|62140|T|P||K638||E|20210312|1040|15|J|0||",
    "X02|K640|123||20210101|001|13118001|20210101|0600|||||||N|85|",
    "X02|K640|123||20210101|002|13113600|20210123|1000|||||||N|85|",
    "X03|K640|123||20210101|R06.3|H|||",
    "X04|K640|123||20210101|AN010||J|1|20210122|1152|13118001||",
    "L01|2021|K640||M|XM"
    ];

    static var fallan110KA =
        [
    "X01|K640|123||20210101|0600|S|19311011|85|W|AT|AT|8605|62140|T|P||K638||E|20210312|1040|15|J|0||",
    "X02|K640|123||20210101|001|13118001|20210101|0600|||||||N|85|",
    "X02|K640|123||20210101|002|13113600|20210123|1000|||||||N|85|",
    "X03|K640|123||20210101|G47.1|H|||",
    "X04|K640|123||20210101|AN011||J|1|20210122|1152||K638|",
    "L01|2021|K638||M|XN"
    ];

    
    func testAN110 () throws {
        var context = try createContextWith(model:2022, lines: lkf2022Tests.fallan100KA)
        try context.execute()
        //let errors = context.errorsWith (code:"WX2Q")
        var result = context.getResultLine(forIndex: 0)
        XCTAssert(result == "X05|K640|123||20210101|HDG05.11|C|134|1584|||14090||||15808")
        context = try createContextWith(model:2022, lines: lkf2022Tests.fallan110KA)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(result == "X05|K640|123||20210101|HDG01.31|A|1547|772|||13067||||15386")
        //XCTAssert(errors == nil, "WX2Q not expected")
        context = try createContextWith(model:2022, lines: lkf2022Tests.fallan100)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(result == "X05|K640|123||20210101|HDG05.11|C|134|1584|||14090||||15808")
        //XCTAssert(errors == nil, "WX2Q not expected")
        context = try createContextWith(model:2022, lines: lkf2022Tests.fallan110)
        try context.execute()
        result = context.getResultLine(forIndex: 0)
        XCTAssert(result == "X05|K640|123||20210101|HDG01.31|A|1547|772|||13067||||15386")
    }
    
    static var fall_physanw = [
        "X01|K714|1234||20220621|1200|I|19960601|80|M|AT|AT|1010|90101|1|P||||8|20220621|1200|11|J|0",
        "X02|K714|1234||20220621|01|16111100|20220621||J||||||N|80|",
        "X03|K714|1234||20220621|A32.0|H|D||",
        "X03|K714|1234||20220621|R99|Z|D||",
        "X04|K714|1234||20220621|AM591||J|0001|20220621|2024|18111600|"
    ]

    static var fall_physanwadd = [
        "X04|K714|1234||20220621|AA010||J|0001|20220621|2024|18111600|"
    ]

    static var fall_physanwadd_accept = [
        "X06|K714|1234||20220621|001:AM591|EX4X"
    ]

    
    func testPhysAnw () throws {
        var context = try createContextWith(model:2022, lines: lkf2022Tests.fall_physanw)
        try context.execute()
        var errors = context.errorsWith (code:"EX4X")
        XCTAssert(errors == nil, "EX4X not expected")
        let err = combine (lkf2022Tests.fall_physanw, lkf2022Tests.fall_physanwadd)
        context = try createContextWith(model:2022, lines: err)
        try context.execute()
        errors = context.errorsWith (code:"EX4X")
        XCTAssert(errors != nil, "EX4X expected")
        context = try createContextWith(model:2022, lines: combine(err, lkf2022Tests.fall_physanwadd_accept))
        try context.execute()
        //errors = context.errorsWith (code:"EX4X")
        errors = context.errorsWith (code:"EX4X")
        XCTAssert(errors == nil, "EX4X not expected (accepted)")
    }

    static var fall_herz = [
        "X01|K640|123||20220101|0600|S|19311011|85|W|AT|AT|8605|62140|T|P||K638||E|20220312|1040|15|J|0||",
        "X02|K640|123||20220101|001|13118001|20220101|0600|||||||N|85|",
        "X02|K640|123||20220101|002|13113600|20220123|1000|||||||N|85|",
        "X03|K640|123||20220101|I50.01|H|||"
    ]
    
    static var fall_herzadd = [
        "X03|K640|123||20220101|I50.12|Z|||"
    ]
    
    func testHerz () throws {
        var context = try createContextWith(model:2022, lines: lkf2022Tests.fall_herz)
        try context.execute()
        var errors = context.errorsWith (code:"WX55")
        XCTAssert(errors != nil, "WX55 expected")
        context = try createContextWith(model:2022, lines: combine (lkf2022Tests.fall_herz, lkf2022Tests.fall_herzadd))
        try context.execute()
        errors = context.errorsWith (code:"WX55")
        XCTAssert(errors == nil, "WX55 not expected")
    }

    static var fall_ambNoGrp =
    [
        "X01|K706|345||20200121|0800|I|19710101|45|W|AT|AT|6410|70357|||||||||18|J|2",
        "X02|K706|345||20200121|001|16111300|20200121|0800|J||||||N|55|123",
        "X04|K706|345||20200121|AP541||J|1|20200121|0800|16111300||123",
        "X04|K706|345||20200121|HF022||J|1|20200121|0800|16111300||12",
        "X04|K706|345||20200121|ZN595||J|1|20200121|0800|16111300||123",
        "X06|K706|345||20200121|000:HF022|WX3P|Warning kann lt. TGF akzeptiert werden"
    ]
    
    static var fall_ambNoGrp2 =
    [
        "X01|K706|345||20200121|0800|I|19710101|45|W|AT|AT|6410|70357|||||||||18|J|2",
        "X02|K706|345||20200121|001|16111300|20200121|0800|J||||||N|55|123",
        "X02|K706|345||20200121|002|16111301|20200121|0800|J||||||N|55|123",
        "X04|K706|345||20200121|AP541||J|1|20200121|0800|16111300||123",
        "X04|K706|345||20200121|HF022||J|1|20200121|0800|16111300||123",
        "X04|K706|345||20200121|HF022||J|1|20200121|0800|16111301||123",
        "X04|K706|345||20200121|ZN595||J|1|20200121|0800|16111300||123",
        "X06|K706|345||20200121|000:HF022|WX3P|Warning kann lt. TGF akzeptiert werden"
    ]

    func testReplaceX06 () throws {
        var context = try createContextWith(model:2020, lines: lkf2022Tests.fall_ambNoGrp)
        _ = lkfcTests.resultForContext(context: context)
        var errors = context.errorsWith (code:"WX3P") // Diagnosen-Kombination
        XCTAssert (errors == nil, "missing warning WX3P")
        
        var output = context.createOutput()
        if (output.count < 7) {
            XCTAssert(false, "invalid output")
        }
        else {
            XCTAssert (output[6].contains("000:HF022"), "X06 not correctly returned")
        }
    
        context.flags |= 256
        _ = lkfcTests.resultForContext(context: context)
        output = context.createOutput()
        if (output.count < 7) {
            XCTAssert(false, "invalid output")
        }
        else {
            XCTAssert (output[6].contains("001:HF022"), "X06 not correctly returned")
        }
        
        context = try createContextWith(model:2020, lines: lkf2022Tests.fall_ambNoGrp2)
        _ = lkfcTests.resultForContext(context: context)
        errors = context.errorsWith (code:"WX3P") // Diagnosen-Kombination
        XCTAssert (errors == nil, "missing warning WX3P")
        
        output = context.createOutput()
        if (output.count < 9) {
            XCTAssert(false, "invalid output")
        }
        else {
            XCTAssert (output[8].contains("000:HF022"), "X06 not correctly returned")
        }
  
        context.flags |= 256
        _ = lkfcTests.resultForContext(context: context)
        errors = context.errorsWith (code:"WX3P") // Diagnosen-Kombination
        XCTAssert (errors == nil, "missing warning WX3P")
        
        output = context.createOutput()
        if (output.count < 10) {
            XCTAssert(false, "invalid output")
        }
        else {
            XCTAssert (output[8].contains("001:HF022"), "X06 not correctly returned")
            XCTAssert (output[9].contains("002:HF022"), "X06 not correctly returned")
        }

        // try again
        _ = lkfcTests.resultForContext(context: context)
        errors = context.errorsWith (code:"WX3P") // Diagnosen-Kombination
        XCTAssert (errors == nil, "missing warning WX3P")
        
        output = context.createOutput()
        if (output.count < 10) {
            XCTAssert(false, "invalid output")
        }
        else {
            XCTAssert (output[8].contains("001:HF022"), "X06 not correctly returned")
            XCTAssert (output[9].contains("002:HF022"), "X06 not correctly returned")
        }
    }

    static var WX3P_revers =
    [
        "X01|K914|123||20220101|1815|S|19811111|55|W|AT|AT|1300| 30740|A|P||||4|20220101|1920|11|J|||",
        "X02|K914|123||20220101|001|11319900|20220101|1815|||||||N|55||00001",
        "X03|K914|123||20220101|O82.1|H|||||00001",
        "X03|K914|123||20220101|301.35|Z|||||00002",
        "X04|K914|123||20220101|JN040||J|1|20220101|1815|17311400||||00001"
    ]

    static var WX3P_revers_accept = ["X06|K914|123||20220101|001:JN040|WX3P|test"]
    
    
    func test_WX3P_SP1 () throws {
        var context = try createContextWith(model:2021, lines: lkf2022Tests.WX3P_revers)
        _ = lkfcTests.resultForContext(context: context)
        var errors = context.errorsWith (code:"WX3P") // Diagnosen-Kombination
        XCTAssert (errors == nil, "WX3P not expected")
        var res = lkfcTests.resultForContext(context: context)
        XCTAssert(res == "X05|K914|123||20220101|MEL13.09|A|||446|30|||||476", "result differs")
        context = try createContextWith(model:2022, lines: lkf2022Tests.WX3P_revers)
        _ = lkfcTests.resultForContext(context: context)
        errors = context.errorsWith (code:"WX3P") // Diagnosen-Kombination
        XCTAssert (errors != nil, "WX3P expected")
        res = lkfcTests.resultForContext(context: context)
        XCTAssert(res == "X05|K914|123||20220101|MEL13.09|A|||446|30|||||476", "result differs")
        let comb = combine(lkf2022Tests.WX3P_revers, lkf2022Tests.WX3P_revers_accept)
        context = try createContextWith(model:2022, lines: comb)
        _ = lkfcTests.resultForContext(context: context)
        errors = context.errorsWith (code:"WX3P") // Diagnosen-Kombination
        XCTAssert (errors == nil, "WX3P accepted")
        res = lkfcTests.resultForContext(context: context)
        XCTAssert(res == "X05|K914|123||20220101|MEL13.09|A|||1002|1034|||||2036", "result differs")

    }
    
    static var fall_adHoc =
    [
        "K01|2024|K901|16111111|1299|Innere Medizin – allgemein|",
        "K01|2024|K901|16111112|1299|Innere Medizin – allgemein|",
        "K01|2024|K901|16211100|1300|Chirurgieambulanz|A",
        "X01|K901|F06||20240101|1200|I|19340101|90|M|AT|AT|1010|90101|1|P||||1|||11|J|2||",
        "X02|K901|F06||20240101|001|16111111|20240101||J||||||N|90|",
        "X04|K901|F06||20240101|DE510||J|1|20240101||16111111||",
        "X04|K901|F06||20240101|DE510||J|1|20240101||16211100||"
                      ]

    static var fall_ambAdHoc2 =
    [
        "X01|K706|345||20210121|0800|I|19710101|45|W|AT|AT|6410|70357|||||||||18|J|2",
        "X02|K706|345||20210121|001|16111300|20210121|0800|J||||||N|55|123",
        "X04|K706|345||20210121|AA510||J|1|20210121|0800|16111300||123",
        "X04|K706|345||20210121|ZD510||J|1|20210121|0800|16111300||12"
    ]

    
    func testAdHoc () throws {
        let context = try createContextWith(model:2024, lines: lkf2022Tests.fall_adHoc)
        let res = lkfcTests.resultForContext(context: context)
        //print(res)
        /*
         context = try createContextWith(model:2021, lines: lkf2022Tests.fall_ambAdHoc2)
         res = lkfcTests.resultForContext(context: context)
         print(res)
         */
    }
 
    
    func testAdHocFile() throws {
        guard let url = URL(string: "file:///Users/alexanderholzer/lkf/testadhoc/lkfdatei.txt") else {
            print ("invalid path")
            return
        }

        let context : LKFContext
        //context.flags = 4096
        do {
            context = try LKFContext(model: 2023, path: "/Users/alexanderholzer/lkf/testadhoc/")
            context.setContextParameters(year: 2023)
            try context.load(file: url, encoding: .ascii)
        }
        catch {
            print (error.localizedDescription)
            return
        }
        
        try context.execute()
        
        let count = context.getAufenthaltCount()
        
        for i in 0..<count {
            let aufenthalt = context[i]
            
            let intresults = aufenthalt.getIntResults()
            for intresult in intresults {
                
                guard let intresult else {
                    continue
                }
                let es = aufenthalt.getErrors()
                for e in es {
                    print (e)
                }
                print ("\(aufenthalt.aufId) -> \(intresult.score)")
            }
            
        }
    }
}
