module VmHelper::TextualSummary
  include TextualMixins::TextualAdvancedSettings
  include TextualMixins::TextualDescription
  include TextualMixins::TextualDrift
  include TextualMixins::TextualFilesystems
  include TextualMixins::TextualGroupTags
  include TextualMixins::TextualInitProcesses
  include TextualMixins::TextualName
  include TextualMixins::TextualOsInfo
  include TextualMixins::TextualPatches
  include TextualMixins::TextualPowerState
  include TextualMixins::TextualProtected
  include TextualMixins::TextualRegion
  include TextualMixins::TextualScanHistory
  include TextualMixins::TextualDevices
  include TextualMixins::TextualCustomButtonEvents
  include TextualMixins::TextualVmmInfo
  include TextualMixins::VmCommon
  # TODO: Determine if DoNav + url_for + :title is the right way to do links, or should it be link_to with :title

  #
  # Groups
  #

  def textual_group_properties
    TextualGroup.new(
      _("Properties"),
      %i[
        id name region server description hostname ipaddress mac_address custom_1 container host_platform
        tools_status load_balancer_health_check_state osinfo devices cpu_affinity snapshots
        advanced_settings resources guid storage_profile protected
      ]
    )
  end

  def flash_reboot_needed
    {:message => _('This virtual machine requires restart.'), :level => 'info'} if @record&.restart_needed
  end

  def textual_id
    { :label => _("ID"), :value => @record.id }
  end

  def textual_group_multi_region
    TextualGroup.new(
      _('Multi Region'),
      %i[region_with_button_link]
    )
  end

  def textual_group_lifecycle
    TextualGroup.new(
      _("Lifecycle"),
      %i[discovered analyzed retirement_date retirement_state provisioned owner group]
    )
  end

  def textual_group_relationships
    TextualGroup.new(
      _("Relationships"),
      %i[
        ems cluster host resource_pool storage service parent_vm genealogy drift scan_history
        cloud_network cloud_subnet custom_button_events
      ]
    )
  end

  def textual_group_vm_cloud_relationships
    TextualGroup.new(
      _("Relationships"),
      %i[
        ems ems_infra cluster host availability_zone cloud_tenant flavor vm_template drift scan_history service genealogy
        cloud_network cloud_subnet placement_group orchestration_stack cloud_networks cloud_subnets network_routers
        security_groups floating_ips network_ports cloud_volumes custom_button_events
      ]
    )
  end

  def textual_group_template_cloud_relationships
    TextualGroup.new(_("Relationships"), %i[ems parent_vm genealogy drift scan_history cloud_tenant custom_button_events])
  end

  def textual_group_security
    TextualGroup.new(_("Security"), %i[users groups patches])
  end

  def textual_group_datastore_allocation
    TextualGroup.new(
      _("Datastore Allocation Summary"),
      %i[disks disks_aligned thin_provisioned allocated_disks allocated_total]
    )
  end

  def textual_group_datastore_usage
    TextualGroup.new(
      _("Datastore Actual Usage Summary"),
      %i[usage_disks usage_snapshots usage_disk_storage usage_overcommitted]
    )
  end

  def textual_group_labels
    TextualGroup.new(_("Labels"), textual_key_value_group(@record.custom_attributes))
  end

  def textual_group_normal_operating_ranges
    TextualCustom.new(
      _("Normal Operating Ranges (over 30 days)"),
      'OperationRanges',
      %i[
        normal_operating_ranges_cpu normal_operating_ranges_cpu_usage normal_operating_ranges_memory
        normal_operating_ranges_memory_usage
      ]
    )
  end

  #
  # Items
  #
  def textual_power_state
    textual_power_state_whitelisted_with_template
  end

  def textual_hostname
    hostnames = @record.hostnames
    {:label => n_("Hostname", "Hostnames", hostnames.size), :value => hostnames.join(", ")}
  end

  def textual_ipaddress
    ips = @record.ipaddresses
    h = {:label    => n_("IP Address", "IP Addresses", ips.size),
         :value    => ips.join(", "),
         :explorer => true}
    if @record.hardware.try(:networks) && @record.hardware.networks.present?
      h[:link] = url_for_only_path(:action => 'show', :id => @record, :display => 'networks')
    end
    h
  end

  def textual_load_balancer_health_check_state
    return nil if @record.try(:load_balancer_health_check_states).blank?
    h = {:label    => _("Load Balancer Status"),
         :value    => @record.load_balancer_health_check_state,
         :title    => @record.load_balancer_health_check_states_with_reason.join("\n"),
         :explorer => true}
    h
  end

  def textual_container
    h = {:label => _("Container")}
    vendor = @record.vendor
    if vendor.blank?
      h[:value] = _("None")
    else
      h[:image] = @record.decorate.fileicon
      h[:title] = _("Show VMM container information")
      h[:explorer] = true
      h[:link] = url_for_only_path(:action => 'show', :id => @record, :display => 'hv_info')

      cpu_details =
        if @record.num_cpu.positive? && @record.cpu_cores_per_socket.positive?
          sockets = n_("%{number} socket", "%{number} sockets", @record.num_cpu) % {:number => @record.num_cpu}
          cores = n_("%{number} core", "%{number} cores", @record.cpu_cores_per_socket) % {:number => @record.cpu_cores_per_socket}
          " (#{sockets} x #{cores})"
        else
          ""
        end
      cpus = n_("%{cpu} CPU", "%{cpu} CPUs", @record.cpu_total_cores) % {:cpu => @record.cpu_total_cores}
      h[:value] = "#{vendor}: #{cpus}#{cpu_details}, #{@record.mem_cpu} MB"
    end
    h
  end

  def textual_host_platform
    {:label => _("Parent Host Platform"),
     :value => (@record.host.nil? ? _("N/A") : @record.v_host_vmm_product)}
  end

  def textual_tools_status
    {:label => _("Platform Tools"), :icon => "pficon pficon-maintenance", :value => (@record.tools_status.nil? ? _("N/A") : @record.tools_status)}
  end

  def textual_cpu_affinity
    {:label => _("CPU Affinity"), :icon => "pficon pficon-cpu", :value => @record.cpu_affinity}
  end

  def textual_storage_profile
    return nil if @record.storage_profile.nil?
    {:label => _("Storage Profile"), :value => @record.storage_profile.name}
  end

  def textual_discovered
    {:label => _("Discovered"), :icon => "fa fa-search", :value => format_timezone(@record.created_on)}
  end

  def textual_analyzed
    {:label => _("Last Analyzed"),
     :icon  => "fa fa-search",
     :value => (@record.last_sync_on.nil? ? _("Never") : format_timezone(@record.last_sync_on))}
  end

  def textual_retirement_date
    return nil if @record.kind_of?(ManageIQ::Providers::Openstack::CloudManager::Template)
    {:label => _("Retirement Date"),
     :icon  => "fa fa-clock-o",
     :value => @record.retires_on.nil? ? _("Never") : format_timezone(@record.retires_on)}
  end

  def textual_retirement_state
    {:label => _("Retirement State"), :value => @record.retirement_state.to_s.capitalize}
  end

  def textual_provisioned
    req = @record.miq_provision.nil? ? nil : @record.miq_provision.miq_request
    return nil if req.nil?
    {:label => _("Provisioned On"), :value => req.fulfilled_on.nil? ? "" : format_timezone(req.fulfilled_on)}
  end

  def textual_owner
    @record.evm_owner.try(:name)
  end

  def textual_group
    {:label => _("Group"), :value => @record.miq_group.try(:description)}
  end

  def textual_cluster
    cluster = @record.try(:ems_cluster)
    return nil if cluster.nil?
    h = {:label => _("Cluster"), :icon => "pficon pficon-cluster", :value => (cluster.nil? ? _("None") : cluster.name)}
    if cluster && role_allows?(:feature => "ems_cluster_show")
      h[:title] = _("Show this VM's Cluster")
      h[:link]  = url_for_only_path(:controller => 'ems_cluster', :action => 'show', :id => cluster)
    end
    h
  end

  def textual_host
    host = @record.host
    return nil if host.nil?
    h = {:label => _("Host"), :icon => "pficon pficon-cluster", :value => (host.nil? ? _("None") : host.name)}
    if host && role_allows?(:feature => "host_show")
      h[:title] = _("Show this VM's Host")
      h[:link]  = url_for_only_path(:controller => 'host', :action => 'show', :id => host)
    end
    h
  end

  def textual_resource_pool
    rp = @record.parent_resource_pool
    h = {:label => _("Resource Pool"), :icon => "pficon pficon-resource-pool", :value => (rp.nil? ? _("None") : rp.name)}
    if rp && role_allows?(:feature => "resource_pool_show")
      h[:title] = _("Show this VM's Resource Pool")
      h[:link]  = url_for_only_path(:controller => 'resource_pool', :action => 'show', :id => rp)
    end
    h
  end

  def textual_storage
    storages = @record.storages
    h = {:label => _('Datastores'), :icon => "fa fa-database"}
    if storages.empty?
      h[:value] = _("None")
    elsif storages.length == 1
      storage = storages.first
      h[:value] = storage.name
      h[:title] = _("Show this VM's Datastores")
      h[:link]  = url_for_only_path(:controller => 'storage', :action => 'show', :id => storage)
    else
      h.delete(:image) # Image will be part of each line item, instead
      main = @record.storage
      h[:value] = storages.sort_by { |s| s.name.downcase }.collect do |s|
        {:icon  => "fa fa-database",
         :value => s.name + (s == main ? ' (main)' : ''),
         :title => _("Show this VM's Datastores"),
         :link  => url_for_only_path(:controller => 'storage', :action => 'show', :id => s)}
      end
    end
    h
  end

  def textual_ems
    textual_link(@record.ext_management_system)
  end

  def textual_ems_infra
    textual_link(@record.ext_management_system.try(:provider).try(:infra_ems))
  end

  def textual_availability_zone
    availability_zone = @record.availability_zone
    h = {:label => _('Availability Zone'),
         :icon  => "pficon pficon-zone",
         :value => (availability_zone.nil? ? _("None") : availability_zone.name)}
    if availability_zone && role_allows?(:feature => "availability_zone_show")
      h[:title] = _("Show this VM's Availability Zone")
      h[:link]  = url_for_only_path(:controller => 'availability_zone', :action => 'show', :id => availability_zone)
    end
    h
  end

  def textual_flavor
    flavor = @record.flavor
    h = {:label => _('Flavor'), :icon => "pficon-flavor", :value => (flavor.nil? ? _("None") : flavor.name)}
    if flavor && role_allows?(:feature => "flavor_show")
      h[:title] = _("Show this VM's Flavor")
      h[:link]  = url_for_only_path(:controller => 'flavor', :action => 'show', :id => flavor)
    end
    h
  end

  def textual_vm_template
    vm_template = @record.genealogy_parent
    h = {:label => _('VM Template'), :icon => "pficon pficon-template", :value => (vm_template.nil? ? _("None") : vm_template.name)}
    if vm_template && role_allows?(:feature => "miq_template_show")
      h[:title] = _("Show this VM's Template")
      h[:link]  = url_for_only_path(:controller => 'miq_template', :action => 'show', :id => vm_template)
    end
    h
  end

  def textual_parent_vm
    return nil unless @record.template?
    h = {:label => _("Parent VM"), :icon => "pficon pficon-virtual-machine"}
    parent_vm = @record.with_relationship_type("genealogy", &:parent)
    if parent_vm.nil?
      h[:value] = _("None")
    else
      h[:value] = parent_vm.name
      h[:title] = _("Show this Image's parent")
      h[:explorer] = true
      url, action = set_controller_action
      h[:link]  = url_for_only_path(:controller => url, :action => action, :id => parent_vm)
    end
    h
  end

  def textual_orchestration_stack
    stack = @record.orchestration_stack
    h = {:label => _('Orchestration Stack'), :icon => "ff ff-stack", :value => (stack.nil? ? _("None") : stack.name)}
    if stack && role_allows?(:feature => "orchestration_stack_show")
      h[:title] = _("Show this VM's Orchestration Stack '%{name}'") % {:name => stack.name}
      h[:link]  = url_for_only_path(:controller => 'orchestration_stack', :action => 'show', :id => stack)
    end
    h
  end

  def textual_service
    h = {:label => _("Service"), :icon => "pficon pficon-service"}
    service = @record.service
    if service.nil?
      h[:value] = _("None")
    else
      h[:value] = service.name
      h[:title] = _("Show this Service")
      h[:link]  = url_for_only_path(:controller => 'service', :action => 'show', :id => service)
    end
    h
  end

  def textual_security_groups
    num   = @record.number_of(:security_groups)
    h     = {:label => _('Security Groups'), :icon => "pficon pficon-cloud-security", :value => num}
    if num.positive? && role_allows?(:feature => "security_group_show_list")
      h[:title] = _("Show all Security Groups")
      h[:explorer] = true
      h[:link]  = url_for_only_path(:action => 'security_groups', :id => @record, :display => "security_groups")
    end
    h
  end

  def textual_floating_ips
    num   = @record.number_of(:floating_ips)
    h     = {:label => _('Floating IPs'), :icon => "ff ff-floating-ip", :value => num}
    if num.positive? && role_allows?(:feature => "floating_ip_show_list")
      h[:title] = _("Show all Floating IPs")
      h[:explorer] = true
      h[:link]  = url_for_only_path(:action => 'floating_ips', :id => @record, :display => "floating_ips")
    end
    h
  end

  def textual_network_routers
    num   = @record.number_of(:network_routers)
    h     = {:label => _('Network Routers'), :icon => "pficon pficon-route", :value => num}
    if num.positive? && role_allows?(:feature => "network_router_show_list")
      h[:title] = _("Show all Network Routers")
      h[:explorer] = true
      h[:link]  = url_for_only_path(:action => 'network_routers', :id => @record, :display => "network_routers")
    end
    h
  end

  def textual_cloud_subnets
    num   = @record.number_of(:cloud_subnets)
    h     = {:label => _('Cloud Subnets'), :icon => "pficon pficon-network", :value => num}
    if num.positive? && role_allows?(:feature => "cloud_subnet_show_list")
      h[:title] = _("Show all Cloud Subnets")
      h[:explorer] = true
      h[:link]  = url_for_only_path(:action => 'cloud_subnets', :id => @record, :display => "cloud_subnets")
    end
    h
  end

  def textual_placement_group
    my_placement_group = @record.placement_group
    h = {:label => _('Placement Group'),
         :icon  => "pficon-flavor",
         :value => (my_placement_group.nil? ? _("None") : my_placement_group.name)}
    if !my_placement_group.nil? && role_allows?(:feature => "placement_group_show")
      h[:title] = _("Show Placement Group")
      textual_link(@record.placement_group, :label => _('Placement Group'))
      h[:link]  = url_for_only_path(:controller => 'placement_group', :action => 'show', :id => my_placement_group.id)
    end
    h
  end

  def textual_network_ports
    num   = @record.number_of(:network_ports)
    h     = {:label => _('Network Ports'), :icon => "ff ff-network-port", :value => num}
    if num.positive? && role_allows?(:feature => "network_port_show_list")
      h[:title] = _("Show all Network Ports")
      h[:explorer] = true
      h[:link]  = url_for_only_path(:action => 'network_ports', :id => @record, :display => "network_ports")
    end
    h
  end

  def textual_cloud_networks
    num   = @record.number_of(:cloud_networks)
    h     = {:label => _('Cloud Networks'), :icon => "ff ff-cloud-network", :value => num}
    if num.positive? && role_allows?(:feature => "cloud_network_show_list")
      h[:title] = _("Show all Cloud Networks")
      h[:explorer] = true
      h[:link]  = url_for_only_path(:action => 'cloud_networks', :id => @record, :display => "cloud_networks")
    end
    h
  end

  def textual_cloud_tenant
    cloud_tenant = @record.cloud_tenant if @record.respond_to?(:cloud_tenant)
    h = {:label => _('Cloud Tenants'), :icon => "pficon pficon-cloud-tenant", :value => (cloud_tenant.nil? ? _("None") : cloud_tenant.name)}
    if cloud_tenant && role_allows?(:feature => "cloud_tenant_show")
      h[:title] = _("Show this VM's Cloud Tenants")
      h[:link]  = url_for_only_path(:controller => 'cloud_tenant', :action => 'show', :id => cloud_tenant)
    end
    h
  end

  def textual_cloud_volumes
    num = @record.number_of(:cloud_volumes)
    h = {:label => _('Cloud Volumes'), :icon => "pficon pficon-volume", :value => num}
    if num.positive? && role_allows?(:feature => "cloud_volume_show_list")
      h[:title]    = _("Show all Cloud Volumes attached to this VM.")
      h[:explorer] = true
      h[:link]     = url_for_only_path(:action => 'cloud_volumes', :id => @record, :display => "cloud_volumes")
    end
    h
  end

  def textual_genealogy
    {
      :label    => _("Genealogy"),
      :icon     => "ff ff-dna",
      :value    => _("Show parent and child VMs"),
      :title    => _("Show virtual machine genealogy"),
      :explorer => true,
      :spinner  => true,
      :link     => url_for_only_path(
        :controller => controller.controller_name,
        :action     => 'show',
        :id         => @record,
        :display    => "vmtree_info"
      )
    }
  end

  def textual_disks
    num = @record.hardware.nil? ? 0 : @record.hardware.number_of(:disks)
    h = {:label => _("Number of Disks"), :icon => "fa fa-hdd-o", :value => num}
    if num.positive?
      h[:title] = n_("Show disk on this VM", "Show disks on this VM", num)
      h[:explorer] = true
      h[:link] = url_for_only_path(:controller => controller.controller_name, :action => 'show', :id => @record, :display => "disks")
    end
    h
  end

  def textual_disks_aligned
    {:label => _("Disks Aligned"), :value => @record.disks_aligned}
  end

  def textual_thin_provisioned
    {:label => _("Thin Provisioning Used"), :value => @record.thin_provisioned.to_s.capitalize}
  end

  def textual_allocated_disks
    h = {:label => _("Disks")}
    value = @record.allocated_disk_storage
    h[:title] = value.nil? ? _("N/A") : "#{number_with_delimiter(value)} bytes"
    h[:value] = value.nil? ? _("N/A") : number_to_human_size(value, :precision => 2)
    h
  end

  def textual_allocated_memory
    h = {:label => _("Memory")}
    value = @record.ram_size_in_bytes_by_state
    h[:title] = value.nil? ? _("N/A") : "#{number_with_delimiter(value)} bytes"
    h[:value] = value.nil? ? _("N/A") : number_to_human_size(value, :precision => 2)
    h
  end

  def textual_allocated_total
    h = textual_allocated_disks
    h[:label] = _("Total Allocation")
    h
  end

  def textual_usage_disks
    textual_allocated_disks
  end

  def textual_usage_memory
    textual_allocated_memory
  end

  def textual_usage_snapshots
    h = {:label => _("Snapshots")}
    value = @record.snapshot_storage
    h[:title] = value.nil? ? _("N/A") : "#{number_with_delimiter(value)} bytes"
    h[:value] = value.nil? ? _("N/A") : number_to_human_size(value, :precision => 2)
    h
  end

  def textual_usage_disk_storage
    h = {:label => _("Total Datastore Used Space")}
    value = @record.used_disk_storage
    h[:title] = value.nil? ? _("N/A") : "#{number_with_delimiter(value)} bytes"
    h[:value] = value.nil? ? _("N/A") : number_to_human_size(value, :precision => 2)
    h
  end

  def textual_usage_overcommitted
    h = {:label => _("Unused/Overcommited Allocation")}
    value = @record.uncommitted_storage
    h[:title] = value.nil? ? _("N/A") : "#{number_with_delimiter(value)} bytes"
    h[:value] = if value.nil?
                  _("N/A")
                else
                  v = number_to_human_size(value.abs, :precision => 2)
                  v = _("(%{value}) * Overallocated") % {:value => v} if value.negative?
                  v
                end
    h
  end

  def textual_normal_operating_ranges_cpu
    h = {:label => _("CPU"), :value => []}
    [:max, _("Max"), :high, _("High"), :avg, _("Average"), :low, _("Low")].each_slice(2) do |key, label|
      value = @record.send("cpu_usagemhz_rate_average_#{key}_over_time_period")
      h[:value] << {:label => label, :value => (value.nil? ? _("Not Available") : mhz_to_human_size(value, 2))}
    end
    h
  end

  def textual_normal_operating_ranges_cpu_usage
    h = {:label => _("CPU Usage"), :value => []}
    [:max, _("Max"), :high, _("High"), :avg, _("Average"), :low, _("Low")].each_slice(2) do |key, label|
      value = @record.send("cpu_usage_rate_average_#{key}_over_time_period")
      h[:value] << {:label => label,
                    :value => (value.nil? ? _("Not Available") : number_to_percentage(value, :precision => 2))}
    end
    h
  end

  def textual_normal_operating_ranges_memory
    h = {:label => _("Memory"), :value => []}
    [:max, _("Max"), :high, _("High"), :avg, _("Average"), :low, _("Low")].each_slice(2) do |key, label|
      value = @record.send("derived_memory_used_#{key}_over_time_period")
      h[:value] << {:label => label,
                    :value => (value.nil? ? _("Not Available") : number_to_human_size(value.megabytes, :precision => 2))}
    end
    h
  end

  def textual_normal_operating_ranges_memory_usage
    h = {:label => _("Memory Usage"), :value => []}
    [:max, _("Max"), :high, _("High"), :avg, _("Average"), :low, _("Low")].each_slice(2) do |key, label|
      value = @record.send("mem_usage_absolute_average_#{key}_over_time_period")
      h[:value] << {:label => label,
                    :value => (value.nil? ? _("Not Available") : number_to_percentage(value, :precision => 2))}
    end
    h
  end
end
