--- include-files.lua – filter to include Markdown files
---
--- Copyright: © 2019–2021 Albert Krewinkel
--- License:   MIT – see LICENSE file for details
-- Module pandoc.path is required and was added in version 2.12
PANDOC_VERSION:must_be_at_least("3.0")

local List = require("pandoc.List")
local path = require("pandoc.path")
local system = require("pandoc.system")

function P(s)
  require("scripts.logging").temp(s)
end

--- Get include auto mode
local include_auto = false
function get_vars(meta)
  if meta["include-auto"] then
    include_auto = true
  end
end

--- Keep last heading level found
local last_heading_level = 0
function update_last_level(header)
  last_heading_level = header.level
end

--- Update contents of included file
local function update_contents(blocks, shift_by, include_path)
  local update_contents_filter = {
    -- Shift headings in block list by given number
    Header = function(header)
      if shift_by then
        header.level = header.level + shift_by
      end
      return header
    end,
    -- If image paths are relative then prepend include file path
    Image = function(image)
      if path.is_relative(image.src) then
        image.src = path.normalize(path.join({ include_path, image.src }))
      end
      return image
    end,
    -- Update path for include-code-files.lua filter style CodeBlocks
    CodeBlock = function(cb)
      if cb.attributes.include and path.is_relative(cb.attributes.include) then
        cb.attributes.include = path.normalize(path.join({ include_path, cb.attributes.include }))
      end
      return cb
    end,
  }
  return pandoc.walk_block(pandoc.Div(blocks), update_contents_filter).content
end

--- Filter function for code blocks
local transclude
function transclude(cb)
  -- ignore code blocks which are not of class "include".
  if not cb.classes:includes("include") then
    return
  end

  -- Markdown is used if this is nil.
  local format = cb.attributes["format"]

  -- Attributes shift headings
  local shift_heading_level_by = 0
  local shift_input = cb.attributes["shift-heading-level-by"]
  if shift_input then
    shift_heading_level_by = tonumber(shift_input)
  else
    if include_auto then
      -- Auto shift headings
      shift_heading_level_by = last_heading_level
    end
  end

  --- keep track of level before recusion
  local buffer_last_heading_level = last_heading_level

  local blocks = List:new()
  for line in cb.text:gmatch("[^\n]+") do
    if line:sub(1, 2) ~= "//" then
      -- local fh = io.open(pandoc.system.get_working_directory() .. line)
      local mt, includecontents = pandoc.mediabag.fetch(line)
      if not includecontents then
        io.stderr:write("Cannot open file " .. line .. " | Skipping includes\n")
      else
        local contents = pandoc.read(includecontents, format).blocks
        last_heading_level = 0
        -- recursive transclusion
        contents = system.with_working_directory(path.directory(line), function()
          return pandoc.walk_block(pandoc.Div(contents), { Header = update_last_level, CodeBlock = transclude })
        end).content
        --- reset to level before recursion
        last_heading_level = buffer_last_heading_level
        blocks:extend(update_contents(contents, shift_heading_level_by, path.directory(line)))
        -- fh:close()
      end
    end
  end
  return blocks
end

return { { Meta = get_vars }, { Header = update_last_level, CodeBlock = transclude } }
