# frozen_string_literal: true

require "regexp-examples"

class Rantly
	module Data
		module Extensions
			REGEXP_EXAMPLES_OPTS = {
				max_group_results: 10,
				max_repeater_variance: 10
			}.freeze

			# @see https://github.com/mnestorov/regex-patterns
			# @return [String]
			FRENCH_PHONE = /\+33[1-9]\d{8}/.freeze
			# @return [String]
			GERMAN_PHONE = /\+49[1-9]\d{3,12}/.freeze
			# @return [String]
			UK_PHONE = /\+44[1-9]\d{9,10}/.freeze
			# @return [String]
			SPANISH_PHONE = /\+34[6-9]\d{8}/.freeze
			# @return [String]
			ITALIAN_PHONE = /\+39[0-9]{9,10}/.freeze

			NON_ASCII_CHAR = /[À-ÿĀ-ſЀ-ӿ一-俿]/.freeze
			ASCII_PRINT_CHAR = /[[:print:]]/.freeze

			SEGMENT_SIZE_GSM7 = 160
			SEGMENT_SIZE_UCS2 = 70

			# @return [String]
			def french_phone
				FRENCH_PHONE.random_example(**REGEXP_EXAMPLES_OPTS)
			end

			# @return [String]
			def german_phone
				GERMAN_PHONE.random_example(**REGEXP_EXAMPLES_OPTS)
			end

			# @return [String]
			def uk_phone
				UK_PHONE.random_example(**REGEXP_EXAMPLES_OPTS)
			end

			# @return [String]
			def spanish_phone
				SPANISH_PHONE.random_example(**REGEXP_EXAMPLES_OPTS)
			end

			# @return [String]
			def italian_phone
				ITALIAN_PHONE.random_example(**REGEXP_EXAMPLES_OPTS)
			end

			# @return [String]
			def non_nanp_phone
				send(
					choose(
						:french_phone, :german_phone, :uk_phone,
						:spanish_phone, :italian_phone
					)
				)
			end

			# @note https://stackoverflow.com/questions/6478875/regular-expression-matching-e-164-formatted-phone-numbers
			# @return [String]
			def nanpa_phone
				"+1" +
					sized(1) { string(/[2-9]/) } +
					sized(2) { string(/[0-9]/) } +
					sized(1) { string(/[2-9]/) } +
					sized(6) { string(/[0-9]/) }
			end

			# @note https://stackoverflow.com/questions/4894198/how-to-generate-a-random-date-in-ruby
			# @return [String]
			def iso8601(from = 0.0, to = Time.now)
				value { Time.at(from + float * (to.to_f - from.to_f)).iso8601 }
			end

			# @return [String]
			def bare_jid
				local = sized(range(3, 12)) { string(:alnum) }
				domain = sized(range(3, 8)) { string(:lower) }
				"#{local}@#{domain}.example.com"
			end

			# @return [String]
			def bw_message_id
				sized(range(6, 19)) { string(:alnum) }
			end

			# @return [String]
			def shortcode
				range(10000, 999999).to_s
			end

			# @return [Array<String>]
			HTTP_ESCAPABLE = " &=?/+@#".chars.freeze

			# @return [String]
			def maybe_http_escapable_string
				base = sized(range(3, 8)) { string(:alnum) }
				choose(
					base,
					base + choose(*HTTP_ESCAPABLE) +
						sized(range(1, 5)) { string(:alnum) }
				)
			end

			# @return [String]
			def media_url
				user_id = sized(range(3, 10)) { string(:alnum) }
				name = sized(range(3, 12)) { string(:alnum) }
				ext = choose(".jpg", ".png", ".gif", ".mp4", ".pdf", ".smil", ".txt", ".xml")
				"https://messaging.bandwidth.com/api/v2/users/#{user_id}/media/#{name}#{ext}"
			end

			# @param ascii_only [Boolean, nil] truthy=force ASCII, nil=random
			# @param nil_pct [Integer] weight (out of 100) for nil result
			# @param empty_pct [Integer] weight (out of 100) for empty string result
			# @return [String, nil]
			def message_body(ascii_only: nil, nil_pct: 2, empty_pct: 2)
				text_pct = 100 - nil_pct - empty_pct

				freq(
					[nil_pct, proc { nil }],
					[empty_pct, proc { "" }],
					[text_pct, proc { _message_body_text(ascii_only: ascii_only) }]
				)
			end

			# @param ascii_only [Boolean, nil]
			# @return [String]
			def _message_body_text(ascii_only: nil)
				use_ascii = ascii_only || boolean
				segment_size = use_ascii ? SEGMENT_SIZE_GSM7 : SEGMENT_SIZE_UCS2
				threshold = segment_size * 3

				len = freq(
					[70, proc { range(1, threshold) }],
					[30, proc { range(threshold + 1, threshold + segment_size * 2) }]
				)

				body = if use_ascii
					       sized(len) { string(:print) }
				       else
					       _utf8_body(len)
				       end

				guard(!body.downcase.match?(BADWORDS))
				body
			end

			# @param length [Integer]
			# @param non_ascii_fraction [Float] 0..1
			# @return [String]
			def _utf8_body(length, non_ascii_fraction = 0.3)
				n_non_ascii = [((length * non_ascii_fraction).ceil), 1].max
				n_ascii = length - n_non_ascii

				ascii_chars = Array.new(n_ascii) {
					ASCII_PRINT_CHAR.random_example(**REGEXP_EXAMPLES_OPTS)
				}
				non_ascii_chars = Array.new(n_non_ascii) {
					NON_ASCII_CHAR.random_example(**REGEXP_EXAMPLES_OPTS)
				}

				(ascii_chars + non_ascii_chars).shuffle.join
			end
		end
	end

	include Data::Extensions
end
