local P=require("\105\110\118\111\107\097\116\105\111\110\046\100\111\116\097\050\046\073\110\118\111\107\101\114")local E=require("\109\111\115\101\115")local C={}local u={FIELD_INTEGER="\110\117\109\098\101\114",FIELD_FLOAT="\110\117\109\098\101\114"}local function F(P,C,u)if P=="\118\097\114\095\116\121\112\101"then return nil end if not P:match("\094\091\097-\122\095\093\043\036")then return nil end if type(C)==u then return true end if E.isTable(C)then local P=(((E.chain(E.isEqual)):partial(u)):overArgs(type)):value()if E.all(C,P)then return true end end return nil end local function Z(P,C)return E.isTable(C)and P or nil end local function r(P)if not E.isString(P.var_type)then return nil end local C=u[P.var_type]local Z=(((E.chain(F)):partialRight(C)):rearg({2,1})):value()return((((E.chain(P)):map(Z)):keys()):value())[1]end local function s(P)local C=E.rearg(Z,{2;1})return((((E.chain(P)):map(C)):keys()):value())[1]end local function G(P)return(((E.chain(P.AbilitySpecial or{})):map(r)):compact()):value()end local function A(P)return(((E.chain(P.AbilitySpecial or{})):map(s)):compact()):value()end local o=E.map(P.ABILITIES_KEY_VALUES,G)local h=E.map(P.ABILITIES_KEY_VALUES,A)local function Y(P)return(((E.chain(P)):map(E.unary(string.len))):max()):value()end function C.dump(P,C)C=C or{}local u=P:GetAssignedHero()local F=C.onlyScaling and h or o local Z=Y(E.keys(F))local r=(((E.chain(F)):map(Y)):max()):value()local s=string.format("\037\037-\037\100\115 \037\037-\037\100\115 \037\037\115",Z,r)for P,E in pairs(F)do local C=u:FindAbilityByName(P)for E,u in ipairs(E)do local F=C:GetSpecialValueFor(u)print(s:format(P,u,F))end end end return C
local Invoker = require("invokation.dota2.Invoker")
local m = require("moses")

local M = {}

local FIELD_TYPES = { FIELD_INTEGER = "number", FIELD_FLOAT = "number" }

local function isSpecialKey(key, value, luaType)
  if key == "var_type" then
    return nil
  end

  if not key:match("^[a-z_]+$") then
    return nil
  end

  if type(value) == luaType then
    return true
  end

  if m.isTable(value) then
    local isLuaType = m.chain(m.isEqual):partial(luaType):overArgs(type):value()

    if m.all(value, isLuaType) then
      return true
    end
  end

  return nil
end

local function isScalingSpecialKey(key, value)
  return m.isTable(value) and key or nil
end

local function extractSpecialKey(special)
  if not m.isString(special.var_type) then
    return nil
  end

  local luaType = FIELD_TYPES[special.var_type]
  local selectSpecialKey = m.chain(isSpecialKey):partialRight(luaType):rearg({ 2, 1 }):value()

  return m.chain(special):map(selectSpecialKey):keys():value()[1]
end

local function extractScalingSpecialKey(special)
  local selectScalingSpecialKey = m.rearg(isScalingSpecialKey, { 2, 1 })
  return m.chain(special):map(selectScalingSpecialKey):keys():value()[1]
end

local function extractSpecials(kv)
  return m.chain(kv.AbilitySpecial or {}):map(extractSpecialKey):compact():value()
end

local function extractScalingSpecials(kv)
  return m.chain(kv.AbilitySpecial or {}):map(extractScalingSpecialKey):compact():value()
end

local SPECIALS = m.map(Invoker.ABILITIES_KEY_VALUES, extractSpecials)
local SCALING = m.map(Invoker.ABILITIES_KEY_VALUES, extractScalingSpecials)

local function maxLen(strings)
  return m.chain(strings):map(m.unary(string.len)):max():value()
end

function M.dump(player, options)
  options = options or {}

  local hero = player:GetAssignedHero()
  local specials = options.onlyScaling and SCALING or SPECIALS
  local maxAbilityLen = maxLen(m.keys(specials))
  local maxSpecialLen = m.chain(specials):map(maxLen):max():value()
  local fmt = string.format("%%-%ds %%-%ds %%s", maxAbilityLen, maxSpecialLen)

  for aName, sNames in pairs(specials) do
    local ability = hero:FindAbilityByName(aName)

    for _, sName in ipairs(sNames) do
      local sValue = ability:GetSpecialValueFor(sName)
      print(fmt:format(aName, sName, sValue))
    end
  end
end

return M
