modules/mobile/app/helpers/mobile/facilities_helper.rb
# frozen_string_literal: true

require 'lighthouse/facilities/v1/client'

module Mobile
  module FacilitiesHelper
    module_function

    # schedulable can be true, false, or nil. Nil returns both schedulable and non-schedulable.
    def fetch_facilities_from_ids(user, facility_ids, include_children:, schedulable:)
      return [] if facility_ids.blank?

      ids = facility_ids.join(',')
      vaos_facilities = VAOS::V2::MobileFacilityService.new(user).get_facilities(ids:, children: include_children,
                                                                                 schedulable:, type: nil)
      vaos_facilities[:data]
    end

    def get_facilities(facility_ids)
      facilities_service.get_facilities(facilityIds: facility_ids.to_a.map { |id| "vha_#{id}" }.join(','))
    end

    def get_facility_names(facility_ids)
      facilities = get_facilities(facility_ids)

      # Create a hash mapping facility IDs to their names
      # Extract ID from format like "vha_123" to just "123"
      facility_map = facilities.each_with_object({}) do |facility, map|
        id = facility.id.sub(/^vha_/, '')
        map[id] = facility.name
      end

      # Map over the original facility_ids to maintain order
      facility_ids.map { |id| facility_map[id.to_s] }
    end

    def facilities_service
      Lighthouse::Facilities::V1::Client.new
    end

    def address_from_facility(facility)
      if facility.type == 'va_health_facility' # for MFS Facilities
        address = facility.physical_address
        street = address[:line].compact.join(', ')
        zip_code = address[:postal_code]
      else
        address = facility.address['physical']
        street = address.slice('address1', 'address2', 'address3', 'address_1', 'address_2',
                               'address_3').values.compact.join(', ')
        zip_code = address['zip']
      end
      Mobile::V0::Address.new(
        street:,
        city: address.symbolize_keys[:city],
        state: address.symbolize_keys[:state],
        zip_code:
      )
    end

    def user_address_coordinates(user)
      address = user.vet360_contact_info&.residential_address
      unless address&.latitude && address.longitude
        raise Common::Exceptions::UnprocessableEntity.new(
          detail: 'User has no home latitude and longitude', source: self.class.to_s
        )
      end

      [address.latitude, address.longitude]
    end

    def blank_location(appointment)
      appointment.location.new(
        name: 'No location provided',
        address: Mobile::V0::Address.new(street: nil, city: nil, state: nil, zip_code: nil),
        phone: nil,
        lat: nil,
        long: nil
      )
    end

    def phone_from_facility(facility)
      phone = facility.phone.symbolize_keys[:main]
      return nil unless phone

      # captures area code (\d{3}) number (\d{3}-\d{4})
      # and optional extension (until the end of the string) (?:\sx(\d*))?$
      phone_captures = phone.match(/^(\d{3})-?(\d{3}-?\d{4})(?:\sx(\d*))?$/)

      Mobile::V0::AppointmentPhone.new(
        area_code: phone_captures[1].presence,
        number: phone_captures[2].presence,
        extension: phone_captures[3].presence
      )
    end

    ##
    # Haversine Distance Calculation
    #
    # Accepts two coordinates in the form
    # of a tuple. I.e.
    #   geo_a  Array(Num, Num)
    #   geo_b  Array(Num, Num)
    #   miles  Boolean
    #
    # Returns the distance between these two
    # points in either miles or kilometers
    def haversine_distance(geo_a, geo_b, miles: true)
      # Get latitude and longitude
      lat1, lon1 = geo_a
      lat2, lon2 = geo_b

      # Calculate radial arcs for latitude and longitude
      d_lat = (lat2 - lat1) * Math::PI / 180
      d_lon = (lon2 - lon1) * Math::PI / 180

      a = (Math.sin(d_lat / 2) *
          Math.sin(d_lat / 2)) +
          (Math.cos(lat1 * Math::PI / 180) *
          Math.cos(lat2 * Math::PI / 180) *
          Math.sin(d_lon / 2) * Math.sin(d_lon / 2))

      c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))

      6371 * c * (miles ? 1 / 1.6 : 1)
    end
  end
end
