local INS = require("inspect")
local ML = require("multipart")

local Fedi = {
  GET = function(auth, url)
    local status, headers, body = Fetch(auth.url .. url, {
      method = "GET",
      headers = { Authorization = "Bearer " .. auth.token },
    })

    return { status = status, headers = headers, body = body }
  end,

  verify_credentials = function(auth)
    local result = Fedi.GET(auth, "/api/v1/accounts/verify_credentials")
    if result.status == 200 then
      return DecodeJson(result.body)
    else
      print(INS(result))
    end
  end,

  connection = function(r)
    if r.session.auth then
      return r.session.auth
    end
  end,

  json = function(params)
    local body = EncodeJson(params)
    if not body then
      body = "{}"
    end

    return {
      method = "POST",
      headers = {
        ["content-type"] = "application/json",
        ["content-length"] = body:len(),
      },
      body = body,
    }
  end,

  multipart = function(params)
    local bound = "multipart/form-data; boundary=----WebShitFormBoundary" .. string.sub(tostring(Lemur64()), 10)
    local multipart = ML("", bound)

    for k, v in pairs(params) do
      if v then
        multipart:set_simple(k, v)
      end
    end

    local body = multipart:tostring()

    return {
      method = "POST",
      headers = {
        ["content-type"] = bound,
        ["content-length"] = body:len(),
      },
      body = body,
    }
  end,

  upload = function(file)
    local bound = "multipart/form-data; boundary=----WebShitFormBoundary" .. string.sub(tostring(Lemur64()), 10)
    local multipart = ML("", bound)
    multipart:set_simple("file", file.content, file.name, file.content_type)
    local body = multipart:tostring()
    return {
      method = "POST",
      headers = {
        ["content-type"] = bound,
        ["content-length"] = body:len(),
      },
      body = body,
    }
  end,

  create_status = function(auth, params)
    local all = params:get_all_with_arrays()
    local media_ids = {}
    if all.file then
      all["file"] = nil
      for _, v in ipairs(params._data.indexes.file) do
        local data = params._data.data[v]
        local headers = data.headers
        local name = string.gmatch(headers[1], 'filename="(.-)"')()
        local content_type = string.gmatch(headers[2], " (.*)")()
        local send = Fedi.upload({ content = data.value, name = name, content_type = content_type })
        send.headers.Authorization = "Bearer " .. auth.token
        local status, _, body = Fetch(auth.url .. "/api/v1/media", send)
        if status == 200 then
          table.insert(media_ids, DecodeJson(body).id)
        end
      end
    end

    if #media_ids > 0 then
      all["media_ids"] = media_ids
    else
      all["media_ids"] = nil
    end

    local send = Fedi.json(all)
    send.headers.Authorization = "Bearer " .. auth.token
    local _status, _headers, _body = Fetch(auth.url .. "/api/v1/statuses", send)
    return { status = _status, headers = _headers, body = _body }
  end,

  search = function(auth, acct)
    local result = Fedi.GET(auth, "/api/v1/accounts/lookup?acct=" .. acct)
    if result.status == 200 then
      return DecodeJson(result.body)
    end
  end,

  build_timeline_url = function(base_path, id, direction, default_params)
    local url = base_path
    local params = {}

    if direction == "old" and id then
      params[#params + 1] = "limit=20"
      params[#params + 1] = "max_id=" .. id
    elseif direction == "new" and id then
      params[#params + 1] = "limit=20"
      params[#params + 1] = "min_id=" .. id
    elseif default_params then
      params[#params + 1] = default_params
    end

    if #params > 0 then
      url = url .. "?" .. table.concat(params, "&")
    end

    return url
  end,

  TWKN = function(auth, id, direction)
    local url = Fedi.build_timeline_url(
      "/api/v1/timelines/public",
      id,
      direction,
      "max_id=FFFFFFFFFFFFFFFFFF&with_muted=true&limit=20"
    )
    local result = Fedi.GET(auth, url)
    if result.status == 200 then
      return DecodeJson(result.body)
    end
  end,

  HOME = function(auth, id, direction)
    local url = Fedi.build_timeline_url(
      "/api/v1/timelines/home",
      id,
      direction,
      "max_id=FFFFFFFFFFFFFFFFFF&with_muted=true&limit=20"
    )
    local result = Fedi.GET(auth, url)
    if result.status == 200 then
      return DecodeJson(result.body)
    end
  end,

  notifications = function(auth, id, direction)
    local url = "/api/v1/notifications?limit=20"
    if id then
      if direction == "new" then
        url = url .. "&min_id=" .. id
      else
        url = url .. "&max_id=" .. id
      end
    end
    local result = Fedi.GET(auth, url)
    if result.status == 200 then
      return DecodeJson(result.body)
    end
  end,

  status = function(auth, id)
    local result = Fedi.GET(auth, "/api/v1/statuses/" .. id)
    if result.status == 200 then
      return DecodeJson(result.body)
    end
  end,

  statuses = function(auth, user_id, post_id, direction)
    local url = Fedi.build_timeline_url("/api/v1/accounts/" .. user_id .. "/statuses/", post_id, direction, nil)
    local result = Fedi.GET(auth, url)
    if result.status == 200 then
      return DecodeJson(result.body)
    end
  end,

  context = function(auth, id)
    local result = Fedi.GET(auth, "/api/v1/statuses/" .. id .. "/context")
    if result.status == 200 then
      local res = DecodeJson(result.body)
      if res then
        local ctx = { parents = res.ancestors, children = res.descendants }

        if ctx.parents[0] == false then
          ctx.parents = {}
        end

        if ctx.children[0] == false then
          ctx.children = {}
        end

        return ctx
      end
      return { children = {}, parents = {} }
    end
  end,

  account = function(auth, account_id)
    local result = Fedi.GET(auth, "/api/v1/accounts/" .. account_id)
    if result.status == 200 then
      return DecodeJson(result.body)
    end
  end,

  search_posts = function(auth, query, account_id, limit)
    limit = limit or 20
    local url = "/api/v2/search?q=" .. EscapePath(query) .. "&type=statuses&limit=" .. limit
    if account_id then
      url = url .. "&account_id=" .. account_id
    end
    local result = Fedi.GET(auth, url)
    if result.status == 200 then
      local data = DecodeJson(result.body)
      if data and data.statuses then
        return data.statuses
      end
    end
    return {}
  end,
}

return Fedi
