# frozen_string_literal: true

module Dor
  class RightsMetadataDS < ActiveFedora::OmDatastream
    require 'dor/rights_auth'

    # This is separate from default_object_rights because
    # (1) we cannot default to such a permissive state
    # (2) this is real, not default
    #
    # Ultimately, default_object_rights should go away and APOs also use an instantation of this class

    set_terminology do |t|
      t.root path: 'rightsMetadata', index_as: [:not_searchable]
      t.copyright proxy: %i[_copyright human], index_as: [:symbol]
      t.use_statement proxy: %i[use use_and_reproduction], index_as: [:symbol]

      t.use do
        t.machine
        t.human
        t.use_and_reproduction path: 'human', attributes: { type: 'useAndReproduction' }
      end

      t._copyright path: 'copyright' do
        t.human
      end

      t._read(path: 'access', attributes: { type: 'read' }) do
        t.machine do
          t.embargo_release_date(path: 'embargoReleaseDate', type: :time)
        end
      end

      t.embargo_release_date(proxy: %i[_read machine embargo_release_date])

      t.creative_commons path: '/use/machine[@type=\'creativeCommons\']', type: 'creativeCommons' do
        t.uri path: '@uri'
      end
      t.creative_commons_human path: '/use/human[@type=\'creativeCommons\']'
      t.open_data_commons path: '/use/machine[@type=\'openDataCommons\']', type: 'openDataCommons' do
        t.uri path: '@uri'
      end
      t.open_data_commons_human path: '/use/human[@type=\'openDataCommons\']'
    end

    def self.xml_template
      Nokogiri::XML::Builder.new do |xml|
        xml.rightsMetadata do
          xml.access(type: 'discover') do
            xml.machine { xml.none }
          end
          xml.access(type: 'read') do
            xml.machine { xml.none } # dark default
          end
          xml.use do
            xml.human(type: 'useAndReproduction')
            xml.human(type: 'creativeCommons')
            xml.machine(type: 'creativeCommons', uri: '')
            xml.human(type: 'openDataCommons')
            xml.machine(type: 'openDataCommons', uri: '')
          end
          xml.copyright { xml.human }
        end
      end.doc
    end

    RIGHTS_TYPE_CODES = {
      'world' => 'World',
      'world-nd' => 'World (no-download)',
      'stanford' => 'Stanford',
      'stanford-nd' => 'Stanford (no-download)',
      'cdl-stanford-nd' => 'Controlled Digital Lending (no-download)',
      'loc:spec' => 'Location: Special Collections',
      'loc:music' => 'Location: Music Library',
      'loc:ars' => 'Location: Archive of Recorded Sound',
      'loc:art' => 'Location: Art Library',
      'loc:hoover' => 'Location: Hoover Library',
      'loc:m&m' => 'Location: Media & Microtext',
      'dark' => 'Dark (Preserve Only)',
      'none' => 'Citation Only'
    }.freeze

    # just a wrapper to invalidate @dra_object
    def content=(xml)
      @dra_object = nil
      super
    end

    def dra_object
      @dra_object ||= Dor::RightsAuth.parse(ng_xml, true)
    end

    # key is the rights type code, used by e.g. RightsMetadataDS#set_read_rights and AdminPolicyObject#default_rights=
    # value is the human-readable string, used for indexing, and for things like building select lists in the argo UI.
    def self.valid_rights_types
      RIGHTS_TYPE_CODES.keys
    end

    def self.valid_rights_type?(rights)
      RightsMetadataDS.valid_rights_types.include? rights
    end

    # a helper method for setting up well-structured rights_xml based on a rights type code
    # @param rights_xml [ng_xml] a nokogiri xml (ruby) object that represents the rights xml for a DOR object
    # @param rights_type [string] a recognized rights type code ('world', 'dark', 'loc:spec', etc)
    def self.upd_rights_xml_for_rights_type(rights_xml, rights_type)
      # Note: The discover node is either 'none' for a dark object or 'world' for any other rights option
      label = rights_type == 'dark' ? 'none' : 'world'
      rights_xml.search('//rightsMetadata/access[@type=\'discover\']/machine').each do |node|
        node.children.remove
        node.add_child Nokogiri::XML::Node.new(label, rights_xml)
      end

      # The read node varies by rights option
      rights_xml.search('//rightsMetadata/access[@type=\'read\']').each do |node|
        node.children.remove
        machine_node = Nokogiri::XML::Node.new('machine', rights_xml)
        node.add_child(machine_node)
        if rights_type.start_with?('world')
          world_node = Nokogiri::XML::Node.new('world', rights_xml)
          world_node.set_attribute('rule', 'no-download') if rights_type.end_with?('-nd')
          machine_node.add_child(world_node)
        elsif rights_type.start_with?('stanford')
          group_node = Nokogiri::XML::Node.new('group', rights_xml)
          group_node.content = 'stanford'
          group_node.set_attribute('rule', 'no-download') if rights_type.end_with?('-nd')
          machine_node.add_child(group_node)
        elsif rights_type.start_with?('loc:')
          loc_node = Nokogiri::XML::Node.new('location', rights_xml)
          loc_node.content = rights_type.split(':').last
          machine_node.add_child(loc_node)
        elsif rights_type.start_with?('cdl')
          cdl_node = Nokogiri::XML::Node.new('cdl', rights_xml)
          group_node = Nokogiri::XML::Node.new('group', cdl_node)
          group_node.content = 'stanford'
          group_node.set_attribute('rule', 'no-download')
          cdl_node.add_child(group_node)
          machine_node.add_child(cdl_node)
        else # we know it is none or dark by the argument filter (first line)
          machine_node.add_child Nokogiri::XML::Node.new('none', rights_xml)
        end
      end
    end

    # @param rights [string] archetypical rights to assign: 'world', 'stanford', 'none', 'dark', etc
    # slight misnomer: also sets discover rights!
    # TODO: convert xpath reads to dra_object calls
    def set_read_rights(rights)
      raise(ArgumentError, "Argument '#{rights}' is not a recognized value") unless RightsMetadataDS.valid_rights_type? rights

      rights_xml = ng_xml
      if rights_xml.search('//rightsMetadata/access[@type=\'read\']').length == 0
        raise('The rights metadata stream doesnt contain an entry for machine read permissions. Consider populating it from the APO before trying to change it.')
      end

      ng_xml_will_change!
      RightsMetadataDS.upd_rights_xml_for_rights_type(rights_xml, rights)

      @dra_object = nil # until TODO complete, we'll expect to have to reparse after modification
    end

    def use_license
      use_license = []
      use_license += Array(creative_commons)
      use_license += Array(open_data_commons)

      use_license.reject(&:blank?)
    end

    def rights
      xml = ng_xml
      if xml.search('//rightsMetadata/access[@type=\'read\']/machine/group').length == 1
        'Stanford'
      elsif xml.search('//rightsMetadata/access[@type=\'read\']/machine/world').length == 1
        'World'
      elsif xml.search('//rightsMetadata/access[@type=\'discover\']/machine/none').length == 1
        'Dark'
      else
        'None'
      end
    end
  end
end
