defmodule Generators.QR do
  @moduledoc false

  use PropCheck

  @capacities %{
    alphanumeric: %{
      low: %{
        1 => 25,
        2 => 47,
        3 => 77,
        4 => 114,
        5 => 154,
        6 => 195,
        7 => 224,
        8 => 279,
        9 => 335,
        10 => 395,
        11 => 468,
        12 => 535,
        13 => 619,
        14 => 667,
        15 => 758,
        16 => 854,
        17 => 938,
        18 => 1046,
        19 => 1153,
        20 => 1249,
        21 => 1352,
        22 => 1460,
        23 => 1588,
        24 => 1704,
        25 => 1853,
        26 => 1990,
        27 => 2132,
        28 => 2223,
        29 => 2369,
        30 => 2520,
        31 => 2677,
        32 => 2840,
        33 => 3009,
        34 => 3183,
        35 => 3351,
        36 => 3537,
        37 => 3729,
        38 => 3927,
        39 => 4087,
        40 => 4296
      },
      medium: %{
        1 => 20,
        2 => 38,
        3 => 61,
        4 => 90,
        5 => 122,
        6 => 154,
        7 => 178,
        8 => 221,
        9 => 262,
        10 => 311,
        11 => 366,
        12 => 419,
        13 => 483,
        14 => 528,
        15 => 600,
        16 => 656,
        17 => 734,
        18 => 816,
        19 => 909,
        20 => 970,
        21 => 1035,
        22 => 1134,
        23 => 1248,
        24 => 1326,
        25 => 1451,
        26 => 1542,
        27 => 1637,
        28 => 1732,
        29 => 1839,
        30 => 1994,
        31 => 2113,
        32 => 2238,
        33 => 2369,
        34 => 2506,
        35 => 2632,
        36 => 2780,
        37 => 2894,
        38 => 3054,
        39 => 3220,
        40 => 3391
      },
      quartile: %{
        1 => 16,
        2 => 29,
        3 => 47,
        4 => 67,
        5 => 87,
        6 => 108,
        7 => 125,
        8 => 157,
        9 => 189,
        10 => 221,
        11 => 259,
        12 => 296,
        13 => 352,
        14 => 376,
        15 => 426,
        16 => 470,
        17 => 531,
        18 => 574,
        19 => 644,
        20 => 702,
        21 => 742,
        22 => 823,
        23 => 890,
        24 => 963,
        25 => 1041,
        26 => 1094,
        27 => 1172,
        28 => 1263,
        29 => 1322,
        30 => 1429,
        31 => 1499,
        32 => 1618,
        33 => 1700,
        34 => 1787,
        35 => 1867,
        36 => 1966,
        37 => 2071,
        38 => 2181,
        39 => 2298,
        40 => 2420
      },
      high: %{
        1 => 10,
        2 => 20,
        3 => 35,
        4 => 50,
        5 => 64,
        6 => 84,
        7 => 93,
        8 => 122,
        9 => 143,
        10 => 174,
        11 => 200,
        12 => 227,
        13 => 259,
        14 => 283,
        15 => 321,
        16 => 365,
        17 => 408,
        18 => 452,
        19 => 493,
        20 => 557,
        21 => 587,
        22 => 640,
        23 => 672,
        24 => 744,
        25 => 779,
        26 => 864,
        27 => 910,
        28 => 958,
        29 => 1016,
        30 => 1080,
        31 => 1150,
        32 => 1226,
        33 => 1307,
        34 => 1394,
        35 => 1431,
        36 => 1530,
        37 => 1591,
        38 => 1658,
        39 => 1774,
        40 => 1852
      }
    },
    byte: %{
      low: %{
        1 => 17,
        2 => 32,
        3 => 53,
        4 => 78,
        5 => 106,
        6 => 134,
        7 => 154,
        8 => 192,
        9 => 230,
        10 => 271,
        11 => 321,
        12 => 367,
        13 => 425,
        14 => 458,
        15 => 520,
        16 => 586,
        17 => 644,
        18 => 718,
        19 => 792,
        20 => 858,
        21 => 929,
        22 => 1003,
        23 => 1091,
        24 => 1171,
        25 => 1273,
        26 => 1367,
        27 => 1465,
        28 => 1528,
        29 => 1628,
        30 => 1732,
        31 => 1840,
        32 => 1952,
        33 => 2068,
        34 => 2188,
        35 => 2303,
        36 => 2431,
        37 => 2563,
        38 => 2699,
        39 => 2809,
        40 => 2953
      },
      medium: %{
        1 => 14,
        2 => 26,
        3 => 42,
        4 => 62,
        5 => 84,
        6 => 106,
        7 => 122,
        8 => 152,
        9 => 180,
        10 => 213,
        11 => 251,
        12 => 287,
        13 => 331,
        14 => 362,
        15 => 412,
        16 => 450,
        17 => 504,
        18 => 560,
        19 => 624,
        20 => 666,
        21 => 711,
        22 => 779,
        23 => 857,
        24 => 911,
        25 => 997,
        26 => 1059,
        27 => 1125,
        28 => 1190,
        29 => 1264,
        30 => 1370,
        31 => 1452,
        32 => 1538,
        33 => 1628,
        34 => 1722,
        35 => 1809,
        36 => 1911,
        37 => 1989,
        38 => 2099,
        39 => 2213,
        40 => 2331
      },
      quartile: %{
        1 => 11,
        2 => 20,
        3 => 32,
        4 => 46,
        5 => 60,
        6 => 74,
        7 => 86,
        8 => 108,
        9 => 130,
        10 => 151,
        11 => 177,
        12 => 203,
        13 => 241,
        14 => 258,
        15 => 292,
        16 => 322,
        17 => 364,
        18 => 394,
        19 => 442,
        20 => 482,
        21 => 509,
        22 => 565,
        23 => 611,
        24 => 661,
        25 => 715,
        26 => 751,
        27 => 805,
        28 => 868,
        29 => 908,
        30 => 982,
        31 => 1030,
        32 => 1112,
        33 => 1168,
        34 => 1228,
        35 => 1283,
        36 => 1351,
        37 => 1423,
        38 => 1499,
        39 => 1579,
        40 => 1663
      },
      high: %{
        1 => 7,
        2 => 14,
        3 => 24,
        4 => 34,
        5 => 44,
        6 => 58,
        7 => 64,
        8 => 84,
        9 => 98,
        10 => 119,
        11 => 137,
        12 => 155,
        13 => 177,
        14 => 194,
        15 => 220,
        16 => 250,
        17 => 280,
        18 => 310,
        19 => 338,
        20 => 382,
        21 => 403,
        22 => 439,
        23 => 461,
        24 => 511,
        25 => 535,
        26 => 593,
        27 => 625,
        28 => 658,
        29 => 698,
        30 => 742,
        31 => 790,
        32 => 842,
        33 => 898,
        34 => 958,
        35 => 983,
        36 => 1051,
        37 => 1093,
        38 => 1139,
        39 => 1219,
        40 => 1273
      }
    }
  }

  def level() do
    oneof([
      :low,
      :medium,
      :quartile,
      :high
    ])
  end

  def version() do
    let version <- range(1, 40) do
      version
    end
  end

  def alphanumeric(size) do
    let charlist <- vector(size, character()) do
      to_string(charlist)
    end
  end

  def get_capacity_for(_mode, _level, 0), do: 0

  def get_capacity_for(mode, level, version) do
    @capacities[mode][level][version]
  end

  defp character() do
    oneof(
      Enum.concat([
        ?0..?9,
        ?a..?z,
        ?A..?Z,
        [?\s, ?$, ?%, ?*, ?+, ?-, ?., ?/, ?:]
      ])
    )
  end
end
