defmodule TelemetryUI.Slug do
  @moduledoc false

  @separator_char ?-

  @doc """
  Return a string in form of a slug for a given string.

  ## Examples

      iex> slugify(" Hi # there ")
      "Hi-there"

      iex> slugify("Über den Wölkchen draußen im Tore")
      "Ueber-den-Woelkchen-draussen-im-Tore"

      iex> slugify("Wikipedia Style", ?_)
      "Wikipedia_Style"

      iex> slugify("_Trimming_and___Removing_inside___")
      "Trimming-and-Removing-inside"

  """
  @spec slugify(text :: any, separator :: char) :: String.t()
  def slugify(text, separator \\ @separator_char) do
    text
    |> handle_possessives()
    |> replace_special_chars()
    |> String.downcase()
    |> remove_unwanted_chars(separator, ~r/([^A-Za-z0-9가-힣])+/)
  end

  defp remove_unwanted_chars(text, separator, pattern) do
    sep_binary = to_string([separator])

    text
    |> String.replace(pattern, sep_binary)
    |> String.trim(sep_binary)
  end

  defp replace_special_chars(text) do
    text
    |> to_charlist()
    |> replace_chars()
    |> to_string()
  end

  # Generate replacement functions using pattern matching.
  replacements = [
    # This file was generated from these two files:
    # https://github.com/easybook/slugger/blob/master/src/Easybook/Slugger.php
    # https://github.com/keyvanakbary/slugifier/blob/master/src/Slugifier.php
    # https://github.com/simov/slugify/blob/master/lib/slugify.js

    # Latin
    {?°, ~c"0"},
    {?æ, ~c"ae"},
    {?ǽ, ~c"ae"},
    {?À, ~c"A"},
    {?Á, ~c"A"},
    {?Â, ~c"A"},
    {?Ã, ~c"A"},
    {?Å, ~c"AA"},
    {?Ǻ, ~c"A"},
    {?Ă, ~c"A"},
    {?Ǎ, ~c"A"},
    {?Æ, ~c"AE"},
    {?Ǽ, ~c"AE"},
    {?à, ~c"a"},
    {?á, ~c"a"},
    {?â, ~c"a"},
    {?ã, ~c"a"},
    {?å, ~c"aa"},
    {?ǻ, ~c"a"},
    {?ă, ~c"a"},
    {?ǎ, ~c"a"},
    {?ª, ~c"a"},
    {?@, ~c"at"},
    {?Ĉ, ~c"C"},
    {?Ċ, ~c"C"},
    {?ĉ, ~c"c"},
    {?ċ, ~c"c"},
    {?Ð, ~c"D"},
    {?Đ, ~c"D"},
    {?ó, ~c"o"},
    {?ð, ~c"d"},
    {?đ, ~c"d"},
    {?È, ~c"E"},
    {?É, ~c"E"},
    {?Ê, ~c"E"},
    {?Ë, ~c"E"},
    {?Ĕ, ~c"E"},
    {?Ė, ~c"E"},
    {?è, ~c"e"},
    {?é, ~c"e"},
    {?ê, ~c"e"},
    {?ë, ~c"e"},
    {?ĕ, ~c"e"},
    {?ė, ~c"e"},
    {?ƒ, ~c"f"},
    {?Ĝ, ~c"G"},
    {?Ġ, ~c"G"},
    {?ĝ, ~c"g"},
    {?ġ, ~c"g"},
    {?Ĥ, ~c"H"},
    {?Ħ, ~c"H"},
    {?ĥ, ~c"h"},
    {?ħ, ~c"h"},
    {?Ì, ~c"I"},
    {?Í, ~c"I"},
    {?Î, ~c"I"},
    {?Ï, ~c"I"},
    {?Ĩ, ~c"I"},
    {?Ĭ, ~c"I"},
    {?Ǐ, ~c"I"},
    {?Į, ~c"I"},
    {?Ĳ, ~c"IJ"},
    {?ì, ~c"i"},
    {?í, ~c"i"},
    {?î, ~c"i"},
    {?ï, ~c"i"},
    {?ĩ, ~c"i"},
    {?ĭ, ~c"i"},
    {?ǐ, ~c"i"},
    {?į, ~c"i"},
    {?ĳ, ~c"ij"},
    {?Ĵ, ~c"J"},
    {?ĵ, ~c"j"},
    {?Ĺ, ~c"L"},
    {?Ľ, ~c"L"},
    {?Ŀ, ~c"L"},
    {?ĺ, ~c"l"},
    {?ľ, ~c"l"},
    {?ŀ, ~c"l"},
    {?Ñ, ~c"N"},
    {?ñ, ~c"n"},
    {?ŉ, ~c"n"},
    {?Ò, ~c"O"},
    {?Ô, ~c"O"},
    {?Õ, ~c"O"},
    {?Ō, ~c"O"},
    {?Ŏ, ~c"O"},
    {?Ǒ, ~c"O"},
    {?Ő, ~c"O"},
    {?Ơ, ~c"O"},
    {?Ø, ~c"OE"},
    {?Ǿ, ~c"O"},
    {?Œ, ~c"OE"},
    {?ò, ~c"o"},
    {?ô, ~c"o"},
    {?õ, ~c"o"},
    {?ō, ~c"o"},
    {?ŏ, ~c"o"},
    {?ǒ, ~c"o"},
    {?ő, ~c"o"},
    {?ơ, ~c"o"},
    {?ø, ~c"oe"},
    {?ǿ, ~c"o"},
    {?º, ~c"o"},
    {?œ, ~c"oe"},
    {?Ŕ, ~c"R"},
    {?Ŗ, ~c"R"},
    {?ŕ, ~c"r"},
    {?ŗ, ~c"r"},
    {?Ŝ, ~c"S"},
    {?Ș, ~c"S"},
    {?ŝ, ~c"s"},
    {?ș, ~c"s"},
    {?ſ, ~c"s"},
    {?Ţ, ~c"T"},
    {?Ț, ~c"T"},
    {?Ŧ, ~c"T"},
    {?Þ, ~c"TH"},
    {?ţ, ~c"t"},
    {?ț, ~c"t"},
    {?ŧ, ~c"t"},
    {?þ, ~c"th"},
    {?Ù, ~c"U"},
    {?Ú, ~c"U"},
    {?Û, ~c"U"},
    {?Ũ, ~c"U"},
    {?Ŭ, ~c"U"},
    {?Ű, ~c"U"},
    {?Ų, ~c"U"},
    {?Ư, ~c"U"},
    {?Ǔ, ~c"U"},
    {?Ǖ, ~c"U"},
    {?Ǘ, ~c"U"},
    {?Ǚ, ~c"U"},
    {?Ǜ, ~c"U"},
    {?ù, ~c"u"},
    {?ú, ~c"u"},
    {?û, ~c"u"},
    {?ũ, ~c"u"},
    {?ŭ, ~c"u"},
    {?ű, ~c"u"},
    {?ų, ~c"u"},
    {?ư, ~c"u"},
    {?ǔ, ~c"u"},
    {?ǖ, ~c"u"},
    {?ǘ, ~c"u"},
    {?ǚ, ~c"u"},
    {?ǜ, ~c"u"},
    {?Ŵ, ~c"W"},
    {?ŵ, ~c"w"},
    {?Ý, ~c"Y"},
    {?Ÿ, ~c"Y"},
    {?Ŷ, ~c"Y"},
    {?ý, ~c"y"},
    {?ÿ, ~c"y"},
    {?ŷ, ~c"y"},
    {?Ç, ~c"C"},
    {?Ó, ~c"O"},
    {?ç, ~c"c"},

    # Arabic
    {?أ, ~c"a"},
    {?ب, ~c"b"},
    {?ت, ~c"t"},
    {?ث, ~c"th"},
    {?ج, ~c"g"},
    {?ح, ~c"h"},
    {?خ, ~c"kh"},
    {?د, ~c"d"},
    {?ذ, ~c"th"},
    {?ر, ~c"r"},
    {?ز, ~c"z"},
    {?س, ~c"s"},
    {?ش, ~c"sh"},
    {?ص, ~c"s"},
    {?ض, ~c"d"},
    {?ط, ~c"t"},
    {?ظ, ~c"th"},
    {?ع, ~c"aa"},
    {?غ, ~c"gh"},
    {?ف, ~c"f"},
    {?ق, ~c"k"},
    {?ك, ~c"k"},
    {?ل, ~c"l"},
    {?م, ~c"m"},
    {?ن, ~c"n"},
    {?ه, ~c"h"},
    {?و, ~c"o"},
    {?ي, ~c"y"},

    # Croatian
    # {?Đ, 'D'}, {?đ, 'd'},

    # Czech
    {?Č, ~c"C"},
    {?Ď, ~c"D"},
    {?Ě, ~c"E"},
    {?Ň, ~c"N"},
    {?Ř, ~c"R"},
    {?Š, ~c"S"},
    {?Ť, ~c"T"},
    {?Ů, ~c"U"},
    {?Ž, ~c"Z"},
    {?č, ~c"c"},
    {?ď, ~c"d"},
    {?ě, ~c"e"},
    {?ň, ~c"n"},
    {?ř, ~c"r"},
    {?š, ~c"s"},
    {?ť, ~c"t"},
    {?ů, ~c"u"},
    {?ž, ~c"z"},

    # Esperanto
    # {?Ĉ, 'C'}, {?ĉ, 'c'}, {?Ŝ, 'S'}, {?ŝ, 's'}, {?Ĥ, 'H'}, {?ĥ, 'h'},
    # {?Ŭ, 'U'}, {?ŭ, 'u'}, {?Ĵ, 'J'}, {?ĵ, 'j'}, {?Ĝ, 'G'}, {?ĝ, 'g'},

    # German
    {?Ä, ~c"Ae"},
    {?Ö, ~c"Oe"},
    {?Ü, ~c"Ue"},
    {?ß, ~c"ss"},
    {?ä, ~c"ae"},
    {?ö, ~c"oe"},
    {?ü, ~c"ue"},

    # Greek
    {?Α, ~c"A"},
    {?Β, ~c"B"},
    {?Γ, ~c"G"},
    {?Δ, ~c"D"},
    {?Ε, ~c"E"},
    {?Ζ, ~c"Z"},
    {?Η, ~c"H"},
    {?Θ, ~c"TH"},
    {?Ι, ~c"I"},
    {?Κ, ~c"K"},
    {?Λ, ~c"L"},
    {?Μ, ~c"M"},
    {?Ν, ~c"N"},
    {?Ξ, ~c"KS"},
    {?Ο, ~c"O"},
    {?Π, ~c"P"},
    {?Ρ, ~c"R"},
    {?Σ, ~c"S"},
    {?Τ, ~c"T"},
    {?Υ, ~c"Y"},
    {?Φ, ~c"F"},
    {?Χ, ~c"X"},
    {?Ψ, ~c"PS"},
    {?Ω, ~c"W"},
    {?Ϊ, ~c"I"},
    {?Ϋ, ~c"Y"},
    {?ά, ~c"a"},
    {?έ, ~c"e"},
    {?ή, ~c"h"},
    {?ί, ~c"i"},
    {?ΰ, ~c"y"},
    {?α, ~c"a"},
    {?β, ~c"b"},
    {?γ, ~c"g"},
    {?δ, ~c"d"},
    {?ε, ~c"e"},
    {?ζ, ~c"z"},
    {?η, ~c"h"},
    {?θ, ~c"th"},
    {?ι, ~c"i"},
    {?κ, ~c"k"},
    {?λ, ~c"l"},
    {?μ, ~c"m"},
    {?ν, ~c"n"},
    {?ξ, ~c"ks"},
    {?ο, ~c"o"},
    {?π, ~c"p"},
    {?ρ, ~c"r"},
    {?ς, ~c"s"},
    {?σ, ~c"s"},
    {?τ, ~c"t"},
    {?υ, ~c"y"},
    {?φ, ~c"f"},
    {?χ, ~c"x"},
    {?ψ, ~c"ps"},
    {?ω, ~c"w"},
    {?ϊ, ~c"i"},
    {?ϋ, ~c"y"},
    {?ό, ~c"o"},
    {?ύ, ~c"y"},
    {?ώ, ~c"w"},
    {?ϒ, ~c"Y"},
    {?Ά, ~c"A"},
    {?Έ, ~c"E"},
    {?Ί, ~c"I"},
    {?Ό, ~c"O"},
    {?Ύ, ~c"Y"},
    {?Ή, ~c"H"},
    {?Ώ, ~c"W"},
    {?ΐ, ~c"i"},

    # Latvian
    {?Ā, ~c"A"},
    {?Ē, ~c"E"},
    {?Ģ, ~c"G"},
    {?Ī, ~c"I"},
    {?Ķ, ~c"K"},
    {?Ļ, ~c"L"},
    {?Ņ, ~c"N"},
    {?Ū, ~c"U"},
    {?ū, ~c"u"},
    # {?Ō, 'O'}, {?ō, 'o'}, {?Ŗ, 'R'}, {?ŗ, 'r'},
    {?ā, ~c"a"},
    {?ē, ~c"e"},
    {?ģ, ~c"g"},
    {?ī, ~c"i"},
    {?ķ, ~c"k"},
    {?ļ, ~c"l"},
    {?ņ, ~c"n"},

    # Lithuanian
    # {?Į, 'I'}, {?į, 'i'}, {?Ų, 'U'}, {?ų, 'u'}, {?Ė, 'E'}, {?ė, 'e'}, {?Ĩ, 'I'}, {?ĩ, 'i'},

    # Maltese
    # {?Ċ, 'C'}, {?ċ, 'c'}, {?Ġ, 'G'}, {?ġ, 'g'}, {?Ħ, 'H'}, {?ħ, 'h'},

    # Polish
    {?Ą, ~c"A"},
    {?Ć, ~c"C"},
    {?Ę, ~c"E"},
    {?Ł, ~c"L"},
    {?Ń, ~c"N"},
    {?Ś, ~c"S"},
    {?Ź, ~c"Z"},
    {?Ż, ~c"Z"},
    {?ą, ~c"a"},
    # {?Ó, 'O'}, {?ó, 'o'},
    {?ć, ~c"c"},
    {?ę, ~c"e"},
    {?ł, ~c"l"},
    {?ń, ~c"n"},
    {?ś, ~c"s"},
    {?ź, ~c"z"},
    {?ż, ~c"z"},

    # Russian
    {?А, ~c"A"},
    {?Б, ~c"B"},
    {?В, ~c"V"},
    {?Г, ~c"G"},
    {?Д, ~c"D"},
    {?Е, ~c"E"},
    {?Ё, ~c"E"},
    {?Ж, ~c"Zh"},
    {?З, ~c"Z"},
    {?И, ~c"I"},
    {?Й, ~c"J"},
    {?К, ~c"K"},
    {?Л, ~c"L"},
    {?М, ~c"M"},
    {?Н, ~c"N"},
    {?О, ~c"O"},
    {?П, ~c"P"},
    {?Р, ~c"R"},
    {?С, ~c"S"},
    {?Т, ~c"T"},
    {?У, ~c"U"},
    {?Ф, ~c"F"},
    {?Х, ~c"H"},
    {?Ц, ~c"C"},
    {?Ч, ~c"Ch"},
    {?Ш, ~c"Sh"},
    {?Щ, ~c"Shch"},
    {?Ъ, ~c""},
    {?Ы, ~c"Y"},
    {?Ь, ~c""},
    {?Э, ~c"E"},
    {?Ю, ~c"Ju"},
    {?Я, ~c"Ja"},
    {?а, ~c"a"},
    {?б, ~c"b"},
    {?в, ~c"v"},
    {?г, ~c"g"},
    {?д, ~c"d"},
    {?е, ~c"e"},
    {?ё, ~c"e"},
    {?ж, ~c"zh"},
    {?з, ~c"z"},
    {?и, ~c"i"},
    {?й, ~c"j"},
    {?к, ~c"k"},
    {?л, ~c"l"},
    {?м, ~c"m"},
    {?н, ~c"n"},
    {?о, ~c"o"},
    {?п, ~c"p"},
    {?р, ~c"r"},
    {?с, ~c"s"},
    {?т, ~c"t"},
    {?у, ~c"u"},
    {?ф, ~c"f"},
    {?х, ~c"h"},
    {?ц, ~c"c"},
    {?ч, ~c"ch"},
    {?ш, ~c"sh"},
    {?щ, ~c"shch"},
    {?ъ, ~c""},
    {?ы, ~c"y"},
    {?ь, ~c""},
    {?э, ~c"e"},
    {?ю, ~c"ju"},
    {?я, ~c"ja"},

    # Sami
    {?Ŋ, ~c"N"},
    {?ŋ, ~c"n"},
    {?Ǧ, ~c"G"},
    {?ǧ, ~c"g"},
    {?Ǩ, ~c"K"},
    {?ǩ, ~c"k"},
    {?Ʒ, ~c"Z"},
    {?ʒ, ~c"z"},
    {?Ǯ, ~c"Z"},
    {?ǯ, ~c"z"},

    # Serbian
    {?ђ, ~c"dj"},
    {?ј, ~c"j"},
    {?љ, ~c"lj"},
    {?њ, ~c"nj"},
    {?ћ, ~c"c"},
    {?џ, ~c"dz"},
    {?Ђ, ~c"Dj"},
    {?Ј, ~c"j"},
    {?Љ, ~c"Lj"},
    {?Њ, ~c"Nj"},
    {?Ћ, ~c"C"},
    {?Џ, ~c"Dz"},

    # Slovak
    # {?Ĺ, 'L'}, {?ĺ, 'l'}, {?Ŕ, 'R'}, {?ŕ, 'r'}, {?Ľ, 'L'}, {?ľ, 'l'}

    # Turkish
    # {?Ç, 'C'}, {?ç, 'c'},
    {?Ğ, ~c"G"},
    {?İ, ~c"I"},
    {?Ş, ~c"S"},
    {?ğ, ~c"g"},
    {?ı, ~c"i"},
    {?ş, ~c"s"},

    # Ukrainian
    {?Є, ~c"Ye"},
    {?І, ~c"I"},
    {?Ї, ~c"Ji"},
    {?Ґ, ~c"G"},
    {?є, ~c"ye"},
    {?і, ~c"i"},
    {?ї, ~c"ji"},
    {?ґ, ~c"g"},

    # Vietnamese
    {?ạ, ~c"a"},
    {?ả, ~c"a"},
    {?ầ, ~c"a"},
    {?ấ, ~c"a"},
    {?ậ, ~c"a"},
    {?ẩ, ~c"a"},
    {?ẫ, ~c"a"},
    {?ằ, ~c"a"},
    {?ắ, ~c"a"},
    {?ặ, ~c"a"},
    {?ẳ, ~c"a"},
    {?ẵ, ~c"a"},
    {?ẹ, ~c"e"},
    {?ẻ, ~c"e"},
    {?ẽ, ~c"e"},
    {?ề, ~c"e"},
    {?ế, ~c"e"},
    {?ệ, ~c"e"},
    {?ể, ~c"e"},
    {?ễ, ~c"e"},
    {?ị, ~c"i"},
    {?ỉ, ~c"i"},
    {?ọ, ~c"o"},
    {?ỏ, ~c"o"},
    {?ồ, ~c"o"},
    {?ố, ~c"o"},
    {?ộ, ~c"o"},
    {?ổ, ~c"o"},
    {?ỗ, ~c"o"},
    {?ờ, ~c"o"},
    {?ớ, ~c"o"},
    {?ợ, ~c"o"},
    {?ở, ~c"o"},
    {?ỡ, ~c"o"},
    {?ụ, ~c"u"},
    {?ủ, ~c"u"},
    {?ừ, ~c"u"},
    {?ứ, ~c"u"},
    {?ự, ~c"u"},
    {?ử, ~c"u"},
    {?ữ, ~c"u"},
    {?ỳ, ~c"y"},
    {?ỵ, ~c"y"},
    {?ỷ, ~c"y"},
    {?ỹ, ~c"y"},
    {?Ạ, ~c"A"},
    {?Ả, ~c"A"},
    {?Ầ, ~c"A"},
    {?Ấ, ~c"A"},
    {?Ậ, ~c"A"},
    {?Ẩ, ~c"A"},
    {?Ẫ, ~c"A"},
    {?Ằ, ~c"A"},
    {?Ắ, ~c"A"},
    {?Ặ, ~c"A"},
    {?Ẳ, ~c"A"},
    {?Ẵ, ~c"A"},
    {?Ẹ, ~c"E"},
    {?Ẻ, ~c"E"},
    {?Ẽ, ~c"E"},
    {?Ề, ~c"E"},
    {?Ế, ~c"E"},
    {?Ệ, ~c"E"},
    {?Ể, ~c"E"},
    {?Ễ, ~c"E"},
    {?Ị, ~c"I"},
    {?Ỉ, ~c"I"},
    {?Ọ, ~c"O"},
    {?Ỏ, ~c"O"},
    {?Ồ, ~c"O"},
    {?Ố, ~c"O"},
    {?Ộ, ~c"O"},
    {?Ổ, ~c"O"},
    {?Ỗ, ~c"O"},
    {?Ờ, ~c"O"},
    {?Ớ, ~c"O"},
    {?Ợ, ~c"O"},
    {?Ở, ~c"O"},
    {?Ỡ, ~c"O"},
    {?Ụ, ~c"U"},
    {?Ủ, ~c"U"},
    {?Ừ, ~c"U"},
    {?Ứ, ~c"U"},
    {?Ự, ~c"U"},
    {?Ử, ~c"U"},
    {?Ữ, ~c"U"},
    {?Ỳ, ~c"Y"},
    {?Ỵ, ~c"Y"},
    {?Ỷ, ~c"Y"},
    {?Ỹ, ~c"Y"},

    # Other
    {?¹, ~c"1"},
    {?², ~c"2"},
    {?³, ~c"3"},
    {?¶, ~c"P"},

    # Currency
    {?€, ~c"euro"},
    {?₢, ~c"cruzeiro"},
    {?₣, ~c"frenchfranc"},
    {?£, ~c"pound"},
    {?₤, ~c"lira"},
    {?₥, ~c"mill"},
    {?₦, ~c"naira"},
    {?₧, ~c"peseta"},
    {?₨, ~c"rupee"},
    {?₩, ~c"won"},
    {?₪, ~c"newshequel"},
    {?₫, ~c"dong"},
    {?₭, ~c"kip"},
    {?₮, ~c"tugrik"},
    {?₯, ~c"drachma"},
    {?₰, ~c"penny"},
    {?₱, ~c"peso"},
    {?₲, ~c"guarani"},
    {?₳, ~c"austral"},
    {?₴, ~c"hryvnia"},
    {?₵, ~c"cedi"},
    {?¢, ~c"cent"},
    {?¥, ~c"yen"},
    {?元, ~c"yuan"},
    {?円, ~c"yen"},
    {?﷼, ~c"rial"},
    {?₠, ~c"ecu"},
    {?¤, ~c"currency"},
    {?฿, ~c"baht"},
    {?$, ~c"dollar"},
    {?Ƀ, ~c"bitcoin"},
    {?₹, ~c"indianrupee"},

    # Symbols
    {?©, ~c"copyright"},
    {?∑, ~c"sum"},
    {?®, ~c"registered"},
    {?†, ~c"+"},
    {?“, ~c"\""},
    {?”, ~c"\""},
    {?‘, ~c"'"},
    {?’, ~c"'"},
    {?∂, ~c"d"},
    {?™, ~c"tm"},
    {?℠, ~c"sm"},
    {?…, ~c"..."},
    {?˚, ~c"o"},
    {?•, ~c"*"},
    {?∆, ~c"delta"},
    {?∞, ~c"infinity"},
    {?♥, ~c"love"},
    {?&, ~c"and"},
    {?|, ~c"or"},
    {?<, ~c"less"},
    {?>, ~c"greater"},
    {?☢, ~c"radioactive"}
  ]

  replacements_by_search =
    replacements
    |> Enum.group_by(fn {search, _} -> search end, fn {_, replace} -> replace end)
    |> Enum.to_list()

  # Create replacement
  for {search, replaces} <- replacements_by_search do
    if search != @separator_char do
      replace = hd(replaces)
      defp replace_chars([unquote(search) | t]), do: unquote(replace) ++ replace_chars(t)
    end
  end

  # A unmatched char will be kept.
  defp replace_chars([h | t]), do: [h] ++ replace_chars(t)

  # String has come to an end, stop recursion here.
  defp replace_chars([]), do: []

  # Handle "Sheep's Milk" so it will be "sheeps-milk" instead of "sheep-s-milk"
  defp handle_possessives(text) do
    String.replace(text, ~r/['’]s/u, "s")
  end
end
