# frozen_string_literal: true

require 'nokogiri'
require 'uri'

module RedmineUxToolkit
  module Services
    class ExternalLinksProcessor
      SAFE_REL_TOKENS = %w[noopener noreferrer].freeze

      def self.enabled?
        settings = Setting.plugin_redmine_ux_toolkit || {}
        settings.fetch('secure_external_links', '1').to_s == '1'
      end

      def initialize(html, current_host)
        @html = html.to_s
        @current_host = current_host.to_s.downcase
      end

      def process
        return html if html.blank? || current_host.blank?

        fragment = Nokogiri::HTML::DocumentFragment.parse(html)
        fragment.css('a[href]').each do |link|
          next unless external_http_link?(link['href'])

          link['target'] = '_blank'
          link['rel'] = merged_rel(link['rel'])
        end

        fragment.to_html
      rescue Nokogiri::XML::SyntaxError, URI::InvalidURIError
        html
      end

      private

      attr_reader :html, :current_host

      def external_http_link?(href)
        uri = URI.parse(href.to_s)
        return false unless %w[http https].include?(uri.scheme)
        return false if uri.host.blank?

        uri.host.downcase != current_host
      rescue URI::InvalidURIError
        false
      end

      def merged_rel(existing_rel)
        tokens = existing_rel.to_s.split(/\s+/).reject(&:blank?)
        (tokens + SAFE_REL_TOKENS).uniq.join(' ')
      end
    end
  end
end
