module Wanderer.Skills

open System

type Skill =
    | Persuasion
    | Combat
    | Ritual
    | Sneaking

type Attribute =
    | Might
    | Will

type RollResult = {
    Succeeded : bool
    Target : int
    Rolls : int list
    AttributeLevel : int
    SkillRank : int
}

let private random = Random()

let roll attribute skill target =
    let rolls = List.init skill (fun _ -> random.Next(6) + 1)
    {
        Succeeded = List.length (List.filter (fun r -> r <= attribute) rolls) >= target
        Target = target
        Rolls = rolls
        AttributeLevel = attribute
        SkillRank = skill
    }

type SuccessLookupKey = {
    Skill : int
    Attr : int
}

let precalculatedSuccessRates =
    [
        ({ Skill = 1; Attr = 2 }, [
            (0, 100.)
            (1, 33.333333333300004)
        ])

        ({ Skill = 2; Attr = 2 }, [
            (0, 100.)
            (1, 55.5555555556)
            (2, 11.111111111200003)
        ])

        ({ Skill = 3; Attr = 2 }, [
            (0, 100.)
            (1, 70.3703703704)
            (2, 25.925925925999998)
            (3, 3.7037037037999987)
        ])

        ({ Skill = 4; Attr = 2 }, [
            (0, 100.)
            (1, 80.2469135802)
            (2, 40.7407407407)
            (3, 11.111111111099998)
            (4, 1.2345679012199984)
        ])

        ({ Skill = 5; Attr = 2 }, [
            (0, 100.)
            (1, 86.8312757202)
            (2, 53.909465020599995)
            (3, 20.987654320999994)
            (4, 4.526748971199993)
            (5, 0.41152263374999265)
        ])

        ({ Skill = 6; Attr = 2 }, [
            (0, 100.)
            (1, 91.22085048011)
            (2, 64.88340192041)
            (3, 31.961591220809993)
            (4, 10.013717421109991)
            (5, 1.7832647462099906)
            (6, 0.13717421122999074)
        ])

        ({ Skill = 7; Attr = 2 }, [
            (0, 100.)
            (1, 94.14723365341)
            (2, 73.66255144031)
            (3, 42.935528120709996)
            (4, 17.329675354409996)
            (5, 4.5267489712099955)
            (6, 0.6858710562599954)
            (7, 0.04572473710099545)
        ])

        ({ Skill = 1; Attr = 3 }, [
            (0, 100.)
            (1, 50.)
        ])

        ({ Skill = 2; Attr = 3 }, [
            (0, 100.)
            (1, 75.)
            (2, 25.)
        ])

        ({ Skill = 3; Attr = 3 }, [
            (0, 100.)
            (1, 87.5)
            (2, 50.)
            (3, 12.5)
        ])

        ({ Skill = 4; Attr = 3 }, [
            (0, 100.)
            (1, 93.75)
            (2, 68.75)
            (3, 31.25)
            (4, 6.25)
        ])

        ({ Skill = 5; Attr = 3 }, [
            (0, 100.)
            (1, 96.875)
            (2, 81.25)
            (3, 50.)
            (4, 18.75)
            (5, 3.125)
        ])

        ({ Skill = 6; Attr = 3 }, [
            (0, 100.)
            (1, 98.4375)
            (2, 89.0625)
            (3, 65.625)
            (4, 34.375)
            (5, 10.9375)
            (6, 1.5625)
        ])

        ({ Skill = 7; Attr = 3 }, [
            (0, 100.)
            (1, 99.21875)
            (2, 93.75)
            (3, 77.34375)
            (4, 50.)
            (5, 22.65625)
            (6, 6.25)
            (7, 0.78125)
        ])

        ({ Skill = 1; Attr = 4 }, [
            (0, 100.)
            (1, 66.6666666667)
        ])

        ({ Skill = 2; Attr = 4 }, [
            (0, 100.)
            (1, 88.8888888889)
            (2, 44.4444444445)
        ])

        ({ Skill = 3; Attr = 4 }, [
            (0, 100.)
            (1, 96.2962962963)
            (2, 74.0740740741)
            (3, 29.6296296297)
        ])

        ({ Skill = 4; Attr = 4 }, [
            (0, 100.)
            (1, 98.76543209877)
            (2, 88.88888888889001)
            (3, 59.259259259290005)
            (4, 19.75308641979)
        ])

        ({ Skill = 5; Attr = 4 }, [
            (0, 100.)
            (1, 99.588477366255)
            (2, 95.47325102880501)
            (3, 79.01234567900501)
            (4, 46.09053497940501)
            (5, 13.168724279805005)
        ])

        ({ Skill = 6; Attr = 4 }, [
            (0, 100.)
            (1, 99.862825788752)
            (2, 98.216735253772)
            (3, 89.986282578872)
            (4, 68.03840877917199)
            (5, 35.116598079571986)
            (6, 8.779149519871986)
        ])

        ({ Skill = 7; Attr = 4 }, [
            (0, 100.)
            (1, 99.9542752629172)
            (2, 99.3141289437582)
            (3, 95.4732510288082)
            (4, 82.6703246456082)
            (5, 57.0644718793082)
            (6, 26.3374485597082)
            (7, 5.852766346608199)
        ])
    ]
    |> Seq.map (fun (key, results) ->
        (key, Map.ofList results))
    |> Map.ofSeq

let getSuccessChance key target =
    match Map.tryFind key precalculatedSuccessRates with
    | None -> 0.
    | Some table ->
        match Map.tryFind target table with
        | None -> 0.
        | Some result -> result