# frozen_string_literal: true

require_relative 'base'
require 'net/http'
require 'json'
require 'time'

class Valvat
  class Lookup
    class HMRC < Base
      ENDPOINT_URL = 'https://api.service.hmrc.gov.uk/organisations/vat/check-vat-number/lookup'
      HEADERS = {
        # https://developer.service.hmrc.gov.uk/api-documentation/docs/reference-guide#versioning
        'Accept' => 'application/vnd.hmrc.1.0+json'
      }.freeze

      def perform
        return { valid: false } unless @options[:uk] == true

        parse(fetch(endpoint_uri).body)
      end

      private

      def endpoint_uri
        endpoint = "/#{@vat.to_s_wo_country}"
        endpoint += "/#{@requester.to_s_wo_country}" if @requester
        URI.parse(ENDPOINT_URL + endpoint)
      end

      def build_request(uri)
        Net::HTTP::Get.new(uri.request_uri, HEADERS)
      end

      def parse(body)
        convert(JSON.parse(body))
      end

      # Return a similar format to VIES
      # Main differences are:
      # - request_date is a (more precise) Time instead of Date
      # - address is newline separated instead of coma (also more precise)
      def convert(raw)
        return build_fault(raw) if raw.key?('code')

        {
          address: format_address(raw.dig('target', 'address')),
          country_code: raw.dig('target', 'address', 'countryCode'),
          name: raw.dig('target', 'name'),
          vat_number: raw.dig('target', 'vatNumber'), valid: true
        }.tap do |hash|
          hash[:request_date] = Time.parse(raw['processingDate']) if raw.key?('processingDate')
          hash[:request_identifier] = raw['consultationNumber'] if raw.key?('consultationNumber')
        end
      end

      # Example raw address from the API:
      # {
      #   "line1": "HM REVENUE AND CUSTOMS",
      #   "line2": "RUBY HOUSE",
      #   "line3": "8 RUBY PLACE",
      #   "line4": "ABERDEEN",
      #   "postcode": "AB10 1ZP",
      #   "countryCode": "GB"
      # }
      def format_address(address)
        address&.values&.join("\n")
      end

      FAULTS = {
        'MESSAGE_THROTTLED_OUT' => RateLimitError,
        'SCHEDULED_MAINTENANCE' => ServiceUnavailable,
        'SERVER_ERROR' => ServiceUnavailable,
        'INVALID_REQUEST' => InvalidRequester,
        'GATEWAY_TIMEOUT' => Timeout
      }.freeze

      def build_fault(raw)
        fault = raw['code']
        return { valid: false } if fault == 'NOT_FOUND'

        exception = FAULTS[fault] || UnknownLookupError
        { error: exception.new("#{fault}#{raw['message'] ? " (#{raw['message']})" : ''}", self.class) }
      end
    end
  end
end