# frozen_string_literal: true

require "test_helper"
require "bandwidth_tn_repo"
require "local_calling_guide_repo"
require "geo_code_repo"

BandwidthTnRepo::DB = Minitest::Mock.new

class BandwidthTnRepoTest < Minitest::Test
	def test_local_inventory_recycled_with_price
		bw_body = Nokogiri::XML::Builder.new { |xml|
			xml.Response {
				xml.TelephoneNumberDetails {
					xml.City "Austin"
					xml.State "TX"
				}
			}
		}.to_xml

		stub_request(
			:get,
			"https://dashboard.bandwidth.com/v1.0/tns/5565555555/tndetails"
		)
			.with(
				headers: {
					"Accept" => "application/xml",
					"Accept-Encoding" => "gzip, compressed",
					"Authorization" => "Bearer test_bw_oauth_token",
					"User-Agent" => "Ruby-Bandwidth-Iris"
				}
			).to_return(status: 200, body: bw_body, headers: {})

		tel = "+15565555555"

		BandwidthTnRepo::DB.expect(
			:exec,
			nil,
			[
				BandwidthTnRepo::STASH_QUERY,
				[tel, "TX", "Austin", "test_bw_account", 10]
			]
		)

		BandwidthTnRepo.new.disconnect(tel, "test").sync

		assert_mock BandwidthTnRepo::DB
	end
	em :test_local_inventory_recycled_with_price

	def test_local_inventory_recycled_no_price
		bw_body = Nokogiri::XML::Builder.new { |xml|
			xml.Response {
				xml.TelephoneNumberDetails {
					xml.City "Austin"
					xml.State "TX"
				}
			}
		}.to_xml

		stub_request(
			:get,
			"https://dashboard.bandwidth.com/v1.0/tns/5575555555/tndetails"
		)
			.with(
				headers: {
					"Accept" => "application/xml",
					"Accept-Encoding" => "gzip, compressed",
					"Authorization" => "Bearer test_bw_oauth_token",
					"User-Agent" => "Ruby-Bandwidth-Iris"
				}
			).to_return(status: 200, body: bw_body, headers: {})

		tel = "+15575555555"

		BandwidthTnRepo::DB.expect(
			:exec,
			nil,
			[
				BandwidthTnRepo::STASH_QUERY,
				[tel, "TX", "Austin", "test_bw_account", 0]
			]
		)

		BandwidthTnRepo.new.disconnect(tel, "test").sync

		assert_mock BandwidthTnRepo::DB
	end
	em :test_local_inventory_recycled_no_price

	def test_stash_falls_back_to_lcg_on_unreadable
		tel = "+15565555555"

		# bw_r bw_l  geo_r geo_l lcg_r lcg_l exp_r exp_l
		[
			["TX",  "Austin", "CA",   "LA",    "NY", "NYC", "TX", "Austin"],
			["TX",  "1City",  "CA",   "LA",    "NY", "NYC", "TX", "LA"],
			["TX",  "1City",  "CA",   "2City", "NY", "NYC", "TX", "NYC"],
			["1ST", "Austin", "CA",   "LA",    "NY", "NYC", "CA", "Austin"],
			["1ST", "1City",  "CA",   "LA",    "NY", "NYC", "CA", "LA"],
			["1ST", "1City",  "CA",   "2City", "NY", "NYC", "CA", "NYC"],
			["1ST", "Austin", "2ST",  "LA",    "NY", "NYC", "NY", "Austin"],
			["1ST", "1City",  "2ST",  "LA",    "NY", "NYC", "NY", "LA"],
			["1ST", "1City",  "2ST",  "2City", "NY", "NYC", "NY", "NYC"],
			["TX",  nil,      "CA",   "LA",    "NY", "NYC", "TX", "LA"],
			["TX",  nil,      "CA",   nil,     "NY", "NYC", "TX", "NYC"],
			[nil,   "Austin", "CA",   "LA",    "NY", "NYC", "CA", "Austin"],
			[nil,   nil,      "CA",   "LA",    "NY", "NYC", "CA", "LA"],
			[nil,   nil,      "CA",   nil,     "NY", "NYC", "CA", "NYC"],
			[nil,   "Austin", nil,    "LA",    "NY", "NYC", "NY", "Austin"],
			[nil,   nil,      nil,    "LA",    "NY", "NYC", "NY", "LA"],
			[nil,   nil,      nil,    nil,     "NY", "NYC", "NY", "NYC"],
			[:error, :error, "CA",   "LA",    "NY", "NYC", "CA", "LA"],
			[:error, :error, "CA",   "2City", "NY", "NYC", "CA", "NYC"],
			[:error, :error, "2ST",  "2City", "NY", "NYC", "NY", "NYC"],
			["TX",  "1City",  :error, :error, "NY", "NYC", "TX", "NYC"],
			["1ST", "Austin", :error, :error, "NY", "NYC", "NY", "Austin"],
			["1ST", "1City",  :error, :error, "NY", "NYC", "NY", "NYC"],
			[nil,   nil,      :error, :error, "NY", "NYC", "NY", "NYC"],
			[:error, :error,  :error, :error, "NY", "NYC", "NY", "NYC"]
		].each do |bw_r, bw_l, geo_r, geo_l, lcg_r, lcg_l, exp_r, exp_l|
			WebMock.reset!
			stub_bw_oauth_token
			stub_bw_tndetails(bw_r, bw_l)

			lcg_body = Nokogiri::XML::Builder.new { |xml|
				xml.root {
					xml.prefixdata {
						xml.send(:"rc-lat", "30.267153")
						xml.send(:"rc-lon", "-97.743061")
						xml.rc(lcg_l)
						xml.region(lcg_r)
					}
				}
			}.to_xml

			stub_request(
				:get,
				"https://localcallingguide.com/xmlprefix.php?npa=556&nxx=555"
			).to_return(status: 200, body: lcg_body)

			stub_geocoder(geo_r, geo_l)

			BandwidthTnRepo::DB.expect(
				:exec,
				nil,
				[
					BandwidthTnRepo::STASH_QUERY,
					[tel, exp_r, exp_l, "test_bw_account", 10]
				]
			)

			BandwidthTnRepo.new(
				local_calling_guide_repo: LocalCallingGuideRepo.new,
				geo_code_repo: GeoCodeRepo.new(memcache: FakeMemcache.new)
			).disconnect(tel, "test").sync

			assert_mock BandwidthTnRepo::DB
		end
	end
	em :test_stash_falls_back_to_lcg_on_unreadable

	def test_rate_center_resolves_region_and_locality_independently
		fake_btn = Struct.new(:telephone_number, :bw_state, :bw_city) {
			def get_details
				{ city: bw_city, state: bw_state }
			end
		}

		fake_prefix = Struct.new(:lat, :lon, :region, :locality) {
			def to_h
				{ "region" => region, "locality" => locality }
			end
		}

		fake_geo_code = Struct.new(:locality, :region) {
			def to_h
				{ locality: locality, region: region }
			end
		}

		fake_lcg_repo = Struct.new(:prefix) {
			def find(_npa, _nxx)
				EMPromise.resolve(prefix)
			end
		}

		fake_geo_repo = Struct.new(:result) {
			def reverse(_lat, _lon)
				EMPromise.resolve(result)
			end
		}

		# bw_r bw_l  geo_r geo_l lcg_r lcg_l exp_r exp_l
		[
			["TX",  "Austin", "CA",   "LA",    "NY", "NYC", "TX", "Austin"],
			["TX",  "1City",  "CA",   "LA",    "NY", "NYC", "TX", "LA"],
			["TX",  "1City",  "CA",   "2City", "NY", "NYC", "TX", "NYC"],
			["1ST", "Austin", "CA",   "LA",    "NY", "NYC", "CA", "Austin"],
			["1ST", "1City",  "CA",   "LA",    "NY", "NYC", "CA", "LA"],
			["1ST", "1City",  "CA",   "2City", "NY", "NYC", "CA", "NYC"],
			["1ST", "Austin", "2ST",  "LA",    "NY", "NYC", "NY", "Austin"],
			["1ST", "1City",  "2ST",  "LA",    "NY", "NYC", "NY", "LA"],
			["1ST", "1City",  "2ST",  "2City", "NY", "NYC", "NY", "NYC"],
			["TX",  nil,      "CA",   "LA",    "NY", "NYC", "TX", "LA"],
			["TX",  nil,      "CA",   nil,     "NY", "NYC", "TX", "NYC"],
			[nil,   "Austin", "CA",   "LA",    "NY", "NYC", "CA", "Austin"],
			[nil,   nil,      "CA",   "LA",    "NY", "NYC", "CA", "LA"],
			[nil,   nil,      "CA",   nil,     "NY", "NYC", "CA", "NYC"],
			[nil,   "Austin", nil,    "LA",    "NY", "NYC", "NY", "Austin"],
			[nil,   nil,      nil,    "LA",    "NY", "NYC", "NY", "LA"],
			[nil,   nil,      nil,    nil,     "NY", "NYC", "NY", "NYC"]
		].each do |bw_r, bw_l, geo_r, geo_l, lcg_r, lcg_l, exp_r, exp_l|
			btn = fake_btn.new("5565555555", bw_r, bw_l)
			prefix = fake_prefix.new(30.0, -97.0, lcg_r, lcg_l)
			geo = fake_geo_code.new(geo_l, geo_r)

			result = BandwidthTnRepo::RateCenter.for(
				btn,
				lcg_repo: fake_lcg_repo.new(prefix),
				geo_code_repo: fake_geo_repo.new(geo)
			).sync

			assert_equal(
				[exp_r, exp_l],
				result.to_a,
				"bw=#{[bw_r, bw_l]} geo=#{[geo_r, geo_l]} " \
				"lcg=#{[lcg_r, lcg_l]}"
			)
		end
	end
	em :test_rate_center_resolves_region_and_locality_independently

	def stub_bw_tndetails(bw_r, bw_l)
		if bw_r == :error
			stub_request(
				:get,
				"https://dashboard.bandwidth.com/v1.0/tns/5565555555/tndetails"
			).to_return(status: 404)
			return
		end

		bw_body = Nokogiri::XML::Builder.new { |xml|
			xml.Response {
				xml.TelephoneNumberDetails {
					xml.City(bw_l) if bw_l
					xml.State(bw_r) if bw_r
				}
			}
		}.to_xml

		stub_request(
			:get,
			"https://dashboard.bandwidth.com/v1.0/tns/5565555555/tndetails"
		)
			.with(
				headers: {
					"Accept" => "application/xml",
					"Accept-Encoding" => "gzip, compressed",
					"Authorization" => "Bearer test_bw_oauth_token",
					"User-Agent" => "Ruby-Bandwidth-Iris"
				}
			).to_return(status: 200, body: bw_body, headers: {})
	end

	def stub_geocoder(geo_r, geo_l)
		if geo_r == :error
			stub_request(
				:get,
				"https://geocoder.ca/?json=1&latt=30.267153&longt=-97.743061"
			).to_return(status: 500)
			return
		end

		geo_json = {
			"latt" => "30.267153",
			"longt" => "-97.743061"
		}
		geo_json["prov"] = geo_r if geo_r
		geo_json["city"] = geo_l if geo_l

		stub_request(
			:get,
			"https://geocoder.ca/?json=1&latt=30.267153&longt=-97.743061"
		).to_return(status: 200, body: geo_json.to_json)
	end
end
