# Copyright 2016 Shawn Neal <sneal@sneal.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# rubocop:disable Metrics/MethodLength

require_relative 'soap'
require_relative 'iso8601_duration'

module WinRM
  module WSMV
    # SOAP header utility mixin
    module Header
      # WSMan URI of the regular Windows cmd shell
      RESOURCE_URI_CMD = 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd'.freeze

      # WSMan URI for PowerShell
      RESOURCE_URI_POWERSHELL = 'http://schemas.microsoft.com/powershell/Microsoft.PowerShell'.freeze

      # Merge the various header hashes and make sure we carry all of the attributes
      # through instead of overwriting them.
      def merge_headers(*headers)
        hdr = {}
        headers.each do |h|
          hdr.merge!(h) do |k, v1, v2|
            v1.merge!(v2) if k == :attributes!
          end
        end
        hdr
      end

      def shared_headers(session_opts)
        {
          "#{SOAP::NS_ADDRESSING}:To" => session_opts[:endpoint],
          "#{SOAP::NS_ADDRESSING}:ReplyTo" => {
            "#{SOAP::NS_ADDRESSING}:Address" =>
              'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous',
            :attributes! => {
              "#{SOAP::NS_ADDRESSING}:Address" => {
                'mustUnderstand' => true
              }
            }
          },
          "#{SOAP::NS_WSMAN_DMTF}:MaxEnvelopeSize" => session_opts[:max_envelope_size],
          "#{SOAP::NS_ADDRESSING}:MessageID" => "uuid:#{SecureRandom.uuid.to_s.upcase}",
          "#{SOAP::NS_WSMAN_MSFT}:SessionId" => "uuid:#{session_opts[:session_id]}",
          "#{SOAP::NS_WSMAN_DMTF}:Locale/" => '',
          "#{SOAP::NS_WSMAN_MSFT}:DataLocale/" => '',
          "#{SOAP::NS_WSMAN_DMTF}:OperationTimeout" =>
            Iso8601Duration.sec_to_dur(session_opts[:operation_timeout]),
          :attributes! => {
            "#{SOAP::NS_WSMAN_DMTF}:MaxEnvelopeSize" => { 'mustUnderstand' => true },
            "#{SOAP::NS_WSMAN_DMTF}:Locale/" => {
              'xml:lang' => session_opts[:locale], 'mustUnderstand' => false
            },
            "#{SOAP::NS_WSMAN_MSFT}:DataLocale/" => {
              'xml:lang' => session_opts[:locale], 'mustUnderstand' => false
            },
            "#{SOAP::NS_WSMAN_MSFT}:SessionId" => { 'mustUnderstand' => false }
          }
        }
      end

      # Helper methods for SOAP Headers

      def resource_uri_shell(shell_uri)
        {
          "#{SOAP::NS_WSMAN_DMTF}:ResourceURI" => shell_uri, :attributes! => {
            "#{SOAP::NS_WSMAN_DMTF}:ResourceURI" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def resource_uri_cmd
        resource_uri_shell(RESOURCE_URI_CMD)
      end

      def resource_uri_wmi(namespace = 'root/cimv2/*')
        {
          "#{SOAP::NS_WSMAN_DMTF}:ResourceURI" =>
          "http://schemas.microsoft.com/wbem/wsman/1/wmi/#{namespace}",
          :attributes! => {
            "#{SOAP::NS_WSMAN_DMTF}:ResourceURI" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_get
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.xmlsoap.org/ws/2004/09/transfer/Get',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_delete
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_command
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_receive
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_send
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Send',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_signal
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_enumerate
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def action_enumerate_pull
        {
          "#{SOAP::NS_ADDRESSING}:Action" =>
          'http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull',
          :attributes! => {
            "#{SOAP::NS_ADDRESSING}:Action" => {
              'mustUnderstand' => true
            }
          }
        }
      end

      def selector_shell_id(shell_id)
        {
          "#{SOAP::NS_WSMAN_DMTF}:SelectorSet" => {
            "#{SOAP::NS_WSMAN_DMTF}:Selector" => shell_id, :attributes! => {
              "#{SOAP::NS_WSMAN_DMTF}:Selector" => {
                'Name' => 'ShellId'
              }
            }
          }
        }
      end
    end
  end
end

# rubocop:enable Metrics/MethodLength
