//
//  lkfc2019SP1tests.swift
//  lkfcTests
//
//  Created by Alex Holzer on 29.11.18.
//  Copyright © 2018 Alexander Holzer. All rights reserved.
//

import XCTest
@testable import lkfc

class lkfc2019SP1tests: XCTestCase {

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

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

    
    static var int0tage1 = [
        "X01|K427|1234||20180102|1443|S|19310501|85|M|AT|AT|4941|41214|A|A||||E|20180112|1612|UB|N|||",
        "X02|K427|1234||20180102|001|11111100|20180102|1443|||||||N|85||00001",
        "X02|K427|1234||20180102|002|12718100|20180105|0851||20180105|1610|1|||N|85||00002",
        "X02|K427|1234||20180102|003|11211100|20180105|1610|||||||N|85||00003",
        "X03|K427|1234||20180102|F10.0|H|||||00001"
    ]
    
    static var int0tage_append = [
        "I11|K427|1234||20180102|002|20180105|00|1|3|0|0|00|0|0|0|0|0|0|1|6,71|7,4|0259|32|1||4|4|044|000000000000000000000|36,5|1|00199|050|0,3|0,73|170|001|5",
        "I12|K427|1234||20180102|002|20180105|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0"
    ]
    
    static var int0tage_append2 = [
        "I11|K427|1234||20180102|002|20180105|00|1|3|0|0|00|0|0|0|0|0|0|1|6,71|7,4|0259|32|1||4|4|044|000000000000000000000|36,5|1|00199|050|0,3|0,73|170|001|5"
    ]


    func createContextWith (model: UInt32, lines : [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith(model:model, lines:lines)
    }
    
    func createContextWith (model: UInt32, year: Int32, lines : [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith(model:model, year: year, lines:lines)
    }
    
    func createContextWith (provider: LKFContextStammProvider, model: UInt32, year: Int32, lines: [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith (provider:provider, model:model, year:year, lines:lines)
    }

    func combine (_ first:[String], _ second:[String]) -> [String] {
        return lkfcTests.combine(first, second)
    }

    
    func resultForContext (context: LKFContext) -> String {
        return lkfcTests.resultForContext (context: context)
    }
    
    func expectErrorCount (context: LKFContext, code:String) -> Int {
        let err = context.errorsWith(code: code)
        return err?.count ?? 0
    }
    
    func expectError (context: LKFContext, code:String) -> Bool {
        return expectErrorCount(context: context, code: code) == 1
    }

    func testIntensiv0() throws {
        
        let stammProvider = LKFContextStammProvider()
        stammProvider.add (file:"spezlist.dat", line:"I2018K42712718100          E2  1285")
        
        
        // 2018: 0-Tage, nicht letzte Abt -> kein Int ok
        var context = try createContextWith(provider: stammProvider, model: 2018, year: 2018, lines: lkfc2019SP1tests.int0tage1)
        try context.execute()
        var s = resultForContext(context: context)
        XCTAssert (s.compare("X05|K427|1234||20180102|HDG20.08|D|44|633|||1758||||2435") == ComparisonResult.orderedSame, "SP1-Int0Tage(2018): result different")
        
        // 2019: EX0P
        context = try createContextWith(provider: stammProvider, model: 2019, year: 2018, lines: lkfc2019SP1tests.int0tage1)
        try context.execute()
        XCTAssert (expectError(context:context, code:"EX0P"), "SP1-Int0Tage(2018): EX0P missing")

        // 2019: ok mit I11+I12
        context = try createContextWith(provider: stammProvider, model: 2019, year: 2018, lines: combine (lkfc2019SP1tests.int0tage1, lkfc2019SP1tests.int0tage_append))
        try context.execute()
        s = resultForContext(context: context)
       // errors = context.getErrors()
        XCTAssert (s.compare("X05|K427|1234||20180102|HDG20.08|D|44|633|||1758||||2435") == ComparisonResult.orderedSame, "SP1-Int0Tage(2018): result different")

        // 2019: EX0P wenn nur I11
        context = try createContextWith(provider: stammProvider, model: 2019, year: 2018, lines: combine (lkfc2019SP1tests.int0tage1, lkfc2019SP1tests.int0tage_append2))
        try context.execute()
        s = resultForContext(context: context)
        // errors = context.getErrors()
        XCTAssert (expectError(context:context, code:"EX0P"), "SP1-Int0Tage(2019): EX0P missing")

    }
    
    static var fall_ex4q_1 = [
        "X01|K214|01||20190101|0120|I|19900101|25|M|AT|AT|9102|20817|||||||||16|J|0",
        "X02|K214|01||20190101|001|17821100|20190101|0120|J||||||N|25|",
        "X02|K214|01||20190101|002|16914400|20190101|0125|J||||||N|25|",
        "X02|K214|01||20190101|003|16111100|20190101|0138|J||||||N|25|",
        "X03|K214|01||20190101|I10|Z|D||",
        "X04|K214|01||20190101|FV010||J|1|20190101|0120|17821100||"
    ]
    
    static var fall_ex4q_add2 = [
        "X03|K214|01||20190101|R51|H|D||"
    ];
    
    static var fall_ex4q_add3 = [
        "X03|K214|01||20190101|T31.0|H|D||"
    ];
    
    static var fall_ex4q_add4 = [
        "X03|K214|01||20190101|R51|H|D||",
        "X03|K214|01||20190101|T31.0|H|D||"
    ];
    
    func testEX4Q_sp1() throws {
        var context = try createContextWith (model: 2018, year: 2019, lines:lkfc2019SP1tests.fall_ex4q_1)
        try context.execute()
        XCTAssert (expectError (context: context, code:"WX3L"), "missing WX3L") // med. leistung ohne plausible diagnose
        
        context = try createContextWith (model: 2019, year: 2019, lines:lkfc2019SP1tests.fall_ex4q_1)
        try context.execute()
        XCTAssert (!expectError (context: context, code:"EX4Q"), "missing EX1K") // EX4Q wurde in 2019.0 retourniert
        XCTAssert (expectError (context: context, code:"EX1K"), "missing EX1K") // SP1: Hauptdiagnose fehlt (statt EX4Q)
        
        context = try createContextWith (model: 2019, year: 2019, lines:combine (lkfc2019SP1tests.fall_ex4q_1, lkfc2019SP1tests.fall_ex4q_add2))
        try context.execute()
        XCTAssert (!expectError (context: context, code:"EX1K"), "EX1K should not be returned") // SP1: Hauptdiagnose fehlt (statt EX4Q)
        
        context = try createContextWith (model: 2019, year: 2019, lines:combine (lkfc2019SP1tests.fall_ex4q_1, lkfc2019SP1tests.fall_ex4q_add3))
        try context.execute()
        XCTAssert (expectError (context: context, code:"EX1M"), "missing EX1M") // SP1: Hauptdiagnose als HD ungueltig
        
        context = try createContextWith (model: 2019, year: 2019, lines:combine (lkfc2019SP1tests.fall_ex4q_1, lkfc2019SP1tests.fall_ex4q_add4))
        try context.execute()
        XCTAssert (expectError (context: context, code:"EX1M"), "EX1M missing") // alle HD muessen Kriterium erfuellen
        XCTAssert (!expectError (context: context, code:"EX1L") , "EX1L should not be returned") // alle HD muessen Kriterium erfuellen
    }
    
    static var fall_hdCount = [
        "X01|K214|01||20190101|0120|I|19900101|25|M|AT|AT|9102|20817|||||||||16|J|0",
        "X02|K214|01||20190101|001|17821100|20190101|0120|J||||||N|25|",
        "X03|K214|01||20190101|R51|H|D||",
        "X03|K214|01||20190101|T31.0|H|D||",
        "X03|K214|01||20190101|I10|Z|D||",
        "X04|K214|01||20190101|FV010||J|1|20190101|0120|17821100||"
    ]
    
    static var fall_hdCount_add1 = [
        "X02|K214|01||20190101|002|16821100|20190101|0125|J||||||N|25|"
    ]

    static var fall_hdCount_add2 = [
        "X02|K214|01||20190101|002|16914400|20190101|0125|J||||||N|25|",
        "X02|K214|01||20190101|003|16111100|20190101|0138|J||||||N|25|"
    ]

    func test_hdCount() throws {
        var context = try createContextWith (model: 2019, year: 2019, lines:lkfc2019SP1tests.fall_hdCount)
        try context.execute()
        XCTAssert (expectError (context: context, code:"EX1L"), "missing EX1L") // HD mehrfach

        context = try createContextWith (model: 2018, year: 2019, lines:lkfc2019SP1tests.fall_hdCount)
        try context.execute()
        let s = resultForContext(context: context)
        XCTAssert (s.compare("X05|K214|01||20190101|AMG17.01|A|66||||||||66") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2019, year: 2019, lines:combine (lkfc2019SP1tests.fall_hdCount,lkfc2019SP1tests.fall_hdCount_add1))
        try context.execute()
        XCTAssert (expectError (context: context, code:"EX1L"), "missing EX1L") // HD mehrfach

        context = try createContextWith (model: 2019, year: 2019, lines:combine (lkfc2019SP1tests.fall_hdCount,lkfc2019SP1tests.fall_hdCount_add2))
        try context.execute()
        XCTAssert (!expectError (context: context, code:"EX1L"), "missing EX1L") // HD mehrfach ok

    }

    static var fall_melleist = [
        "X01|K214|01||20190101|0120|I|19900101|25|M|AT|AT|9102|20817|||||||||16|J|0",
        "X02|K214|01||20190101|001|17821100|20190101|0120|J||||||N|25|",
         "X03|K214|01||20190101|R51|H|D||"
    ]
    static var fall_melleist_k01 = ["K01|2019|K214|17821100|100|Test|A"]
    static var fall_melleist_other_k01 = ["K01|2019|K214|17841100|100|Test|A"]
    static var fall_melleist_kafc = ["X04|K214|01||20190101|FV010||J|1|20190101|0120|17821100|K901|"]
    static var fall_melleist_fc = ["X04|K214|01||20190101|FV010||J|1|20190101|0120|17821100||"]

    static var fall_melleist_bett = ["X04|K214|01||20190101|BL540||J|1|20190101|0120|11211100||"]
    
    static var fall_melleist_stat = [
        "X01|K427|1234||20180102|1443|S|19310501|85|M|AT|AT|4941|41214|A|A||||E|20180112|1612|UB|N|||",
        "X02|K427|1234||20180102|001|11111100|20180102|1443|||||||N|85||00001",
        "X03|K427|1234||20180102|F10.0|H|||||00001"
    ]
    
    static var fall_melleist_stat_bett1 = ["X04|K427|1234||20180102|BL540||J|1|20180105|0120|11211100||"]
    static var fall_melleist_stat_bett2 = ["X04|K427|1234||20180102|BD039|L|J|1|20180105|0120|11211100||"]
    static var fall_melleist_stat_bett3 = ["X04|K427|1234||20180102|BD039|L|J|1|20180105|0120|17821100||"]
    
    func testMELFC() throws {
        
        let kafc = combine(lkfc2019SP1tests.fall_melleist, lkfc2019SP1tests.fall_melleist_kafc)
        let nok01 = combine(lkfc2019SP1tests.fall_melleist, lkfc2019SP1tests.fall_melleist_fc)
        let withOtherk01 = combine(lkfc2019SP1tests.fall_melleist_other_k01, nok01)
        let withk01 = combine(lkfc2019SP1tests.fall_melleist_k01, nok01)
       
        var context = try createContextWith (model: 2019, year: 2019, lines: kafc)
        try context.execute()
        XCTAssert (expectError (context: context, code:"WX52"), "missing WX52") // MEL: FCLEIST und KANR gemeldet

        context = try createContextWith (model: 2018, year: 2019, lines: kafc)
        try context.execute()
        var s = resultForContext(context: context)
        XCTAssert (s.compare("X05|K214|01||20190101|AMG17.01|A|66||||||||66") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2019, year: 2019, lines: nok01)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (s.compare("X05|K214|01||20190101|AMG17.01|A|66||||||||66") == ComparisonResult.orderedSame, "result different")
        
        context = try createContextWith (model: 2019, year: 2019, lines: withOtherk01)
        try context.execute()
        XCTAssert (expectError (context: context, code:"WX53"), "missing WX53") // FCLEIST nicht im KOSTPLAN

        context = try createContextWith (model: 2018, year: 2019, lines: withOtherk01)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (s.compare("X05|K214|01||20190101|AMG17.01|A|66||||||||66") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2019, year: 2019, lines: withk01)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (s.compare("X05|K214|01||20190101|AMG17.01|A|66||||||||66") == ComparisonResult.orderedSame, "result different")

        let amb_wx51 = combine(lkfc2019SP1tests.fall_melleist, lkfc2019SP1tests.fall_melleist_bett)
        
        let stat_wx51_melok = combine(lkfc2019SP1tests.fall_melleist_stat, lkfc2019SP1tests.fall_melleist_stat_bett1)
        let stat_wx51_melnok = combine(lkfc2019SP1tests.fall_melleist_stat, lkfc2019SP1tests.fall_melleist_stat_bett2)
        let stat_wx51_okamb = combine(lkfc2019SP1tests.fall_melleist_stat, lkfc2019SP1tests.fall_melleist_stat_bett3)

        context = try createContextWith (model: 2019, year: 2019, lines: amb_wx51)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (expectError (context: context, code:"WX51"), "missing WX51") // Betten-FC ung
        XCTAssert (s.compare("X05|K214|01||20190101|APG02.00|A||34|||||||34") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2018, year: 2019, lines: amb_wx51)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (!expectError (context: context, code:"WX51"), "missing WX51") // Betten-FC ung
        XCTAssert (s.compare("X05|K214|01||20190101|APG02.00|A||34|||||||34") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2019, year: 2018, lines: stat_wx51_melok)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (!expectError (context: context, code:"WX51"), "missing WX51") // Betten-FC ung
        XCTAssert (s.compare("X05|K427|1234||20180102|HDG20.08|D|44|633|||1758||||2435") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2019, year: 2018, lines: stat_wx51_melnok)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (expectError (context: context, code:"WX51"), "missing WX51") // Betten-FC ung
        XCTAssert (s.compare("X05|K427|1234||20180102|HDG20.08|D|44|633|||1758||||2435") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2018, year: 2018, lines: stat_wx51_melnok)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (!expectError (context: context, code:"WX51"), "missing WX51") // Betten-FC ung
        XCTAssert (s.compare("X05|K427|1234||20180102|HDG20.08|D|44|633|||1758||||2435") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2019, year: 2018, lines: stat_wx51_okamb)
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (!expectError (context: context, code:"WX51"), "missing WX51") // Betten-FC ung
        XCTAssert (s.compare("X05|K427|1234||20180102|HDG20.08|D|44|633|||1758||||2435") == ComparisonResult.orderedSame, "result different")

        context = try createContextWith (model: 2019, year: 2019, lines: amb_wx51)
        context.flags = 4096 // NFonds
        try context.execute()
        s = resultForContext(context: context)
        XCTAssert (!expectError (context: context, code:"WX51"), "WX51 for nf") // Betten-FC ung
        XCTAssert (s.compare("X05|K214|01||20190101|APG02.00|A||34|||||||34") == ComparisonResult.orderedSame, "result different")

    }
    
    
    static var fall_wx4w_wx53 = [
        "K01|2019|K714|17821100|100|Test|A",
        "X01|K714|1234||20181230|1200|S|19360501|80|M|AT|AT|1010|90101|A|P||||E|20190102|1200|11|J|0",
        "X02|K714|1234||20181230|01|11111100|20181230||J||||||N|80|",
        "X03|K714|1234||20181230|I51.9|H|D||",
        "X03|K714|1234||20181230|R53|Z|D||"]
    
    static var fall_wx53_akt = ["X04|K714|1234||20181230|BE039|L|J|0001|20190101|2024|18111600|"]
    static var fall_wx53_prev = ["X04|K714|1234||20181230|BE039|L|J|0001|20181231|2024|18111600|"]
    static var fall_wx4w_prev = ["X04|K714|1234||20181230|BE039|L|J|0001|20181231|2024||"]
    static var fall_wx4w_akt = ["X04|K714|1234||20181230|BE039|L|J|0001|20190101|2024||"]

    func testWX4W () throws {
        var context = try createContextWith (model: 2019, year: 2019, lines: combine(lkfc2019SP1tests.fall_wx4w_wx53,lkfc2019SP1tests.fall_wx53_akt))
        try context.execute()
        XCTAssert (expectError(context:context, code:"WX53"), "FCLEIST nicht im KOST(akt.Periode)->WX53 fehlt!")
        
        context = try createContextWith (model: 2019, year: 2019, lines: combine(lkfc2019SP1tests.fall_wx4w_wx53,lkfc2019SP1tests.fall_wx53_prev))
        try context.execute()
        XCTAssert (!expectError(context:context, code:"WX53"), "FCLEIST nicht im KOST(Vorperiode)->kein WX53 in SP2")

        context = try createContextWith (model: 2019, year: 2019, lines: combine(lkfc2019SP1tests.fall_wx4w_wx53,lkfc2019SP1tests.fall_wx4w_prev))
        try context.execute()
        XCTAssert (expectError(context:context, code:"WX4W"), "FCLEIST leer (Vorperiode)-> WX4W fehlt")

        context = try createContextWith (model: 2019, year: 2019, lines: combine(lkfc2019SP1tests.fall_wx4w_wx53,lkfc2019SP1tests.fall_wx4w_akt))
        try context.execute()
        XCTAssert (expectError(context:context, code:"WX4W"), "FCLEIST leer (akt.Periode)->WX4W fehlt!")

        context = try createContextWith (model: 2018, year: 2019, lines: combine(lkfc2019SP1tests.fall_wx4w_wx53,lkfc2019SP1tests.fall_wx4w_prev))
        try context.execute()
        XCTAssert (expectError(context:context, code:"WX4W"), "FCLEIST leer (Vorperiode/Mod.2018)-> WX4W fehlt")

        
    }
    
    static var fall_kaskore_crash = ["K01|2017|K315|11127711|900002|HG Pulmologie Stat. A|A",
                                     "K01|2017|K315|11127721|900004|HG Pulmologie Stat. E|A",
                                     "K01|2017|K515|11127731|900001|HG Pulmologie Stat. K|A",
                                     "K19|2017|K315|11127741|900011|HG Schlaflabor|A",
                                     "K01|2017|K315|11631111|900007|HG Neurologie Stat. B|A"]
    
    func testKASKORECrash() throws {
        let context = try createContextWith (model: 2017, year: 2017, lines: lkfc2019SP1tests.fall_kaskore_crash)
        try context.execute()
        XCTAssert (expectError (context: context, code:"FATD"), "missing FATD") // Satzart ungueltig
    }
     
    static var fall_EK82_14 = ["K01|2019|K706|14626801|16221|PS-Psych|H"],
               fall_EK82_16 = ["K01|2019|K706|16626801|16222|PS-Psych|H"],
               fall_FAT2 =    ["K01|2019|K706|14914700|16223|PS-Psych|H"];

    func testEK82 () throws {
        var context = try createContextWith (model: 2019, year: 2019, lines: lkfc2019SP1tests.fall_EK82_14)
        try context.execute()
        XCTAssert (!expectError (context: context, code:"EK82"), "EK82 should not be returned")
        context = try createContextWith (model: 2018, year: 2019, lines: lkfc2019SP1tests.fall_EK82_16)
        try context.execute()
        XCTAssert (expectError (context: context, code:"EK82"), "EK82 should be returned")
        context = try createContextWith (model: 2019, year: 2019, lines: lkfc2019SP1tests.fall_EK82_16)
        try context.execute()
        XCTAssert (!expectError (context: context, code:"EK82"), "EK82 should not be returned")
        context = try createContextWith (model: 2019, year: 2019, lines: lkfc2019SP1tests.fall_FAT2)
        try context.execute()
        XCTAssert (expectError (context: context, code:"FAT2"), "missing FAT2")
    }
   
    static var fall_sharpDiagSP2ZD = [
        "X01|K201|234||20170301|1749|I|20060516|10|M|AT|AT|9363|20518|||||||||56|J|2",
        "X02|K201|234||20170301|001|16221100|20170301|1749|J||||||N|10|",
        "X03|K201|234||20170301|S61.0|H|D||",
        "X03|K201|234||20170301|929.9|Z|D||",
        "X03|K201|234||20170301|Z00.0|Z|D||",
        "X04|K201|234||20170301|AJ010|L|J|1|20170301|1800|16221100||",
        "X04|K201|234||20170301|QZ760||J|1|20170301|1749|16221100||",
        "X04|K201|234||20170301|ZZ531||J|1|20170301|1843|16221100||"
        ]

    static var fall_sharpDiagSP2HD = [
        "X01|K201|123||20170205|1749|I|20060516|10|M|AT|AT|9363|20518|||||||||56|J|2",
        "X02|K201|123||20170205|001|16221100|20170205|1749|J||||||N|10|",
        "X03|K201|123||20170205|S61.0|Z|D||",
        "X03|K201|123||20170205|929.9|Z|D||",
        "X03|K201|123||20170205|Z00.0|H|D||",
        "X04|K201|123||20170205|AJ010|L|J|1|20170205|1800|16221100||",
        "X04|K201|123||20170205|QZ760||J|1|20170205|1749|16221100||",
        "X04|K201|123||20170205|ZZ531||J|1|20170205|1843|16221100||"
    ]
    
    func testSharpDiagSP2() throws {
        var context = try createContextWith (model: 2019, year: 2017, lines: lkfc2019SP1tests.fall_sharpDiagSP2ZD)
        try context.execute()
        XCTAssert (!expectError (context: context, code:"EX1N"), "ZD: EX1N not returned with SP2")
        let s = resultForContext(context: context)
        XCTAssert (s.compare("X05|K201|234||20170301|AMG00.90|B|542|60|||||48||650") == ComparisonResult.orderedSame, "result different")
        context = try createContextWith (model: 2019, year: 2017, lines: lkfc2019SP1tests.fall_sharpDiagSP2HD)
        try context.execute()
        XCTAssert (!expectError (context: context, code:"EX1N"), "HD: EX1N not returned with SP2")
    }
}
