

#load "load.fsx"


#time



open MathNet.Numerics
open Informedica.Utils.Lib
open Informedica.Utils.Lib.BCL
open Informedica.GenForm.Lib
open Informedica.GenUnits.Lib
open Informedica.GenSolver.Lib
open Informedica.GenOrder.Lib




let path = Some $"{__SOURCE_DIRECTORY__}/log.txt"
let startLogger () =
    // Start the logger at an informative level
    OrderLogger.logger.Start path Logging.Level.Informative
let stopLogger () = OrderLogger.logger.Stop ()



let test pat n =
    let pr =
        pat
        |> PrescriptionRule.get
        |> Array.filter (fun pr -> pr.DoseRule.Products |> Array.isEmpty |> not)
        |> Array.item n

    pr
    |> Api.evaluate { Log = ignore }
    |> Array.map (function
        | Ok (ord, pr) ->
            let ns =
                pr.DoseRule.DoseLimits
                |> Array.map (fun dl -> dl.Substance)
            let o =
                ord
                |> Order.Print.printPrescription ns
            let p =
                $"{pr.DoseRule.Generic}, {pr.DoseRule.Shape}, {pr.DoseRule.DoseType |> DoseType.toString} {pr.DoseRule.Indication}"
            Ok (pat, p, o)
        | Error (ord, pr, m) ->
            let o =
                ord
                |> Order.toString
                |> String.concat "\n"
            let p =
                $"{pr.DoseRule.Generic}, {pr.DoseRule.Shape}, {pr.DoseRule.Indication}"

            Error ($"%A{m}", p, o)
    )




let getN pat =
    pat
    |> PrescriptionRule.get
    |> Array.filter (fun pr -> pr.DoseRule.Products |> Array.isEmpty |> not)
    |> Array.length


let run n pat =
    for i in [0..n-1] do
        try
            i
            |> test pat
            |> Array.map (function
                | Ok (pat, ind, (prs, prep, adm)) ->
                    [
                        ""
                        $"{i}"
                        $"Patient: {pat |> Patient.toString}"
                        $"Indicatie: {ind}"
                        $"Voorschrift: {prs}"
                        if prep |> String.notEmpty then $"Bereiding: {prep}"
                        $"Toediening: {adm}"
                        ""
                    ]
                    |> String.concat "\n"
                | Error (_, p, _) -> $"\n{i}.Fail: {p}\n"
            )
            |> String.concat "\n"

        with
        | _ ->
            let pr =
                pat
                |> PrescriptionRule.get
                |> Array.filter (fun pr -> pr.DoseRule.Products |> Array.isEmpty |> not)
                |> Array.item i
                |> fun pr ->
                    $"{pr.DoseRule.Generic}, {pr.DoseRule.Shape}, {pr.DoseRule.Indication}"

            $"\n{i}. could not calculate: {pr}\n"
        |>  File.appendTextToFile path.Value


let getRule i pat =
    pat
    |> PrescriptionRule.get
    |> Array.filter (fun pr -> pr.DoseRule.Products |> Array.isEmpty |> not)
    |> Array.item i



[
    Patient.premature
    Patient.newBorn
    Patient.infant
    Patient.toddler
    Patient.child
    Patient.teenager
    Patient.adult
]
// |> List.skip 4
// |> List.take 1
|> List.iter (fun pat ->
    let n = getN pat
    printfn $"=== Running pat: {pat |> Patient.toString}: {n} ==="

    pat
    |> run n
)


test Patient.premature 111
|> Array.iter (function
    | Ok (pat, ind, (prs, prep, adm)) ->
        [
            $"Patient: {pat |> Patient.toString}"
            $"Indicatie: {ind}"
            $"Voorschrift: {prs}"
            if prep |> String.notEmpty then $"Bereiding: {prep}"
            $"Toediening: {adm}"
        ]
        |> List.iter (printfn "%s")
    | Error _ -> ()
)


startLogger ()
stopLogger ()


Patient.premature
|> getRule 111 //|> Api.evaluate (OrderLogger.logger.Logger)
|> fun pr -> pr |> Api.createDrugOrder None //(pr.SolutionRules[0] |> Some)  //|> printfn "%A"
|> DrugOrder.toOrder
|> Order.Dto.fromDto
|> Order.applyConstraints //|> Order.toString |> List.iter (printfn "%s")
|> Order.solveMinMax true OrderLogger.logger.Logger
|> function
| Error (ord, msgs) ->
    printfn "oeps error"
    // printfn $"{msgs |> List.map string}"
    // ord
    // |> Order.toString
    // |> String.concat "\n"
    // |> printfn "%s"

| Ok ord  ->
//    ord.Orderable.OrderableQuantity
//    |> printfn "%A"

    ord
    |> Order.toString
    |> String.concat "\n"
    |> printfn "%s"



open Order

try
    let ord =
        Patient.child
        |> getRule 703
        |> Api.createDrugOrder None
        |> DrugOrder.toOrder
        |> Order.Dto.fromDto
        |> Order.applyConstraints

    let mapping =
        match ord.Prescription with
        | Continuous -> Mapping.continuous
        | Discontinuous _ -> Mapping.discontinuous
        | Timed _ -> Mapping.timed
        |> Mapping.getEquations
        |> Mapping.getEqsMapping ord

    printfn $"{mapping}"

    let oEqs =
        ord
        |> mapToEquations mapping

    oEqs
    |> Solver.mapToSolverEqs



with
| :? Informedica.GenSolver.Lib.Exceptions.SolverException as e ->
    printfn $"{e.Data0}"
    raise e



let testDto =
    Patient.infant
    |> getRule 5
    |> Api.createDrugOrder None
    |> DrugOrder.toOrder




Patient.infant
|> Api.getIndications
|> Array.iter (printfn "%s")


Patient.infant
|> Api.getGenerics
|> Array.iter (printfn "%s")



Patient.child
|> Demo.scenarioResult
|> Demo.filter
|> fun scr -> 
    { scr with
        Generics = 
            scr.Generics 
            |> Array.filter ((=) "cotrimoxazol")
    }
|> Demo.filter


// failing case
Patient.adult
|> PrescriptionRule.get 
|> Array.filter (fun pr -> pr.DoseRule.Generic = "amfotericine-b-liposomaal")
|> Array.head 
|> Api.evaluate OrderLogger.logger.Logger


Informedica.ZIndex.Lib.GenPresProduct.search "cotrimoxazol"


DoseRule.get ()
|> Array.filter (fun dr -> dr.Products |> Array.isEmpty)
|> Array.map (fun dr -> 
    $"{dr.Generic} {dr.Shape}",
    Informedica.ZIndex.Lib.GenPresProduct.search dr.Generic
    |> Array.map (fun gpp -> 
        $"{gpp.Name |> String.toLower} {gpp.Shape |> String.toLower}"
    )
    |> Array.distinct
    |> String.concat ", "
)
|> Array.distinct
|> Array.sort
|> Array.iter (fun (g, ns) -> printfn $"{g}:{ns}")