class IDRAC::Firmware

def upload_firmware(firmware_path)

def upload_firmware(firmware_path)
  puts "Uploading firmware file: #{firmware_path}".light_cyan
  
  begin
    # First, get the HttpPushUri from the UpdateService
    response = client.authenticated_request(
      :get,
      "/redfish/v1/UpdateService"
    )
    
    if response.status != 200
      puts "Failed to get UpdateService information: #{response.status}".red
      raise Error, "Failed to get UpdateService information: #{response.status}"
    end
    
    update_service = JSON.parse(response.body)
    http_push_uri = update_service['HttpPushUri']
    
    if http_push_uri.nil?
      puts "HttpPushUri not found in UpdateService".red
      raise Error, "HttpPushUri not found in UpdateService"
    end
    
    puts "Found HttpPushUri: #{http_push_uri}".light_cyan
    
    # Get the ETag for the firmware inventory
    etag_response = client.authenticated_request(
      :get,
      http_push_uri
    )
    
    if etag_response.status != 200
      puts "Failed to get ETag: #{etag_response.status}".red
      raise Error, "Failed to get ETag: #{etag_response.status}"
    end
    
    etag = etag_response.headers['ETag']
    
    if etag.nil?
      puts "ETag not found in response headers".yellow
      # Some iDRACs don't require ETag, so we'll continue
    else
      puts "Got ETag: #{etag}".light_cyan
    end
    
    # Upload the firmware file
    file_content = File.read(firmware_path)
    
    headers = {
      'Content-Type' => 'multipart/form-data',
      'If-Match' => etag
    }
    
    # Create a temp file for multipart upload
    upload_io = Faraday::UploadIO.new(firmware_path, 'application/octet-stream')
    payload = { :file => upload_io }
    
    upload_response = client.authenticated_request(
      :post,
      http_push_uri,
      {
        headers: headers,
        body: payload,
      }
    )
    
    if upload_response.status != 201 && upload_response.status != 200
      puts "Failed to upload firmware: #{upload_response.status} - #{upload_response.body}".red
      
      if upload_response.body.include?("already in progress")
        raise Error, "A deployment or update operation is already in progress. Please wait for it to complete before attempting another update."
      else
        raise Error, "Failed to upload firmware: #{upload_response.status} - #{upload_response.body}"
      end
    end
    
    # Extract the firmware ID from the response
    begin
      upload_data = JSON.parse(upload_response.body)
      firmware_id = upload_data['Id'] || upload_data['@odata.id']&.split('/')&.last
      
      if firmware_id.nil?
        # Try to extract from the Location header
        location = upload_response.headers['Location']
        firmware_id = location&.split('/')&.last
      end
      
      if firmware_id.nil?
        puts "Warning: Could not extract firmware ID from response".yellow
        puts "Response body: #{upload_response.body}"
        # We'll try to continue with the SimpleUpdate action anyway
      else
        puts "Firmware file uploaded successfully with ID: #{firmware_id}".green
      end
    rescue JSON::ParserError => e
      puts "Warning: Could not parse upload response: #{e.message}".yellow
      puts "Response body: #{upload_response.body}"
      # We'll try to continue with the SimpleUpdate action anyway
    end
    
    # Now initiate the firmware update using SimpleUpdate action
    puts "Initiating firmware update using SimpleUpdate...".light_cyan
    
    # Construct the image URI
    image_uri = nil
    
    if firmware_id
      image_uri = "#{http_push_uri}/#{firmware_id}"
    else
      # If we couldn't extract the firmware ID, try using the Location header
      image_uri = upload_response.headers['Location']
    end
    
    # If we still don't have an image URI, try to use the HTTP push URI as a fallback
    if image_uri.nil?
      puts "Warning: Could not determine image URI, using HTTP push URI as fallback".yellow
      image_uri = http_push_uri
    end
    
    puts "Using ImageURI: #{image_uri}".light_cyan
    
    # Initiate the SimpleUpdate action
    simple_update_payload = {
      "ImageURI" => image_uri,
      "TransferProtocol" => "HTTP"
    }
    
    update_response = client.authenticated_request(
      :post,
      "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
      {
        headers: { 'Content-Type' => 'application/json' },
        body: simple_update_payload.to_json
      }
    )
    
    if update_response.status != 202 && update_response.status != 200
      puts "Failed to initiate firmware update: #{update_response.status} - #{update_response.body}".red
      raise Error, "Failed to initiate firmware update: #{update_response.status} - #{update_response.body}"
    end
    
    # Extract the job ID from the response
    job_id = nil
    
    # Try to extract from the response body first
    begin
      update_data = JSON.parse(update_response.body)
      job_id = update_data['Id'] || update_data['JobID']
    rescue JSON::ParserError
      # If we can't parse the body, that's okay, we'll try other methods
    end
    
    # If we couldn't get the job ID from the body, try the Location header
    if job_id.nil?
      location = update_response.headers['Location']
      job_id = location&.split('/')&.last
    end
    
    # If we still don't have a job ID, try the response headers
    if job_id.nil?
      # Some iDRACs return the job ID in a custom header
      update_response.headers.each do |key, value|
        if key.downcase.include?('job') && value.is_a?(String) && value.match?(/JID_\d+/)
          job_id = value
          break
        end
      end
    end
    
    # If we still don't have a job ID, check for any JID_ pattern in the response body
    if job_id.nil? && update_response.body.is_a?(String)
      match = update_response.body.match(/JID_\d+/)
      job_id = match[0] if match
    end
    
    # If we still don't have a job ID, check the task service for recent jobs
    if job_id.nil?
      puts "Could not extract job ID from response, checking task service for recent jobs...".yellow
      
      tasks_response = client.authenticated_request(
        :get,
        "/redfish/v1/TaskService/Tasks"
      )
      
      if tasks_response.status == 200
        begin
          tasks_data = JSON.parse(tasks_response.body)
          
          if tasks_data['Members'] && tasks_data['Members'].any?
            # Get the most recent task
            most_recent_task = tasks_data['Members'].first
            task_id = most_recent_task['@odata.id']&.split('/')&.last
            
            if task_id && task_id.match?(/JID_\d+/)
              job_id = task_id
              puts "Found recent job ID: #{job_id}".light_cyan
            end
          end
        rescue JSON::ParserError
          # If we can't parse the tasks response, we'll have to give up
        end
      end
    end
    
    if job_id.nil?
      puts "Could not extract job ID from response".red
      raise Error, "Could not extract job ID from response"
    end
    
    puts "Firmware update job created with ID: #{job_id}".green
    return job_id
  rescue => e
    puts "Error during firmware upload: #{e.message}".red.bold
    raise Error, "Error during firmware upload: #{e.message}"
  end
end