local M = {}
local filter = require "make4ht-filter"
local mkutils = require "mkutils"
local log = logging.new "staticsite"

-- get the published file name
local function get_slug(settings)
  local published_name = mkutils.remove_extension(settings.tex_file) .. ".published"
  local config = get_filter_settings "staticsite"
  local file_pattern = config.file_pattern or "%Y-%m-%d-${input}"
  local time = os.time()

  -- we must save the published date, so the subsequent compilations at different days
  -- use the same name
  if mkutils.file_exists(published_name) then
    local f = io.open(published_name, "r")
    local readtime  = f:read("*line")
    time = tonumber(readtime)
    log:info("Already pubslished", os.date("%Y-%m-%d %H:%M", time))
    f:close()
  else
    -- escape 
    -- slug must contain the unescaped input name
    local f = io.open(published_name, "w")
    log:info("Publishing article", os.date("%Y-%m-%d %H:%M", time))
    f:write(time)
    f:close()
  end
  -- set the updated and publishing times
  local updated
  -- the updated time will be set only when it is more than one day from the published time
  local newtime = os.time()
  if (newtime - time) > (24 * 3600) then updated = newtime end
  filter_settings "staticsite" {
    header = {
      time = time,
      updated = updated
    }
  }

  -- make the output file name in the format YYYY-MM-DD-old-filename.html
  local slug = os.date(file_pattern,time) % settings
  return slug
end


-- it is necessary to set correct -jobname in latex_par parameters field
-- in order to the get correct HTML file name
local function update_jobname(slug, latex_par)
  local latex_par = latex_par or ""
  if latex_par:match("%-jobname") then
    local firstchar=latex_par:match("%-jobname=.")
    local replace_pattern="%-jobname=[^%s]+"
    if firstchar == "'" or firstchar=='"' then
      replace_pattern = "%-jobname=".. firstchar .."[^%"..firstchar.."]+"
    end
    
    return latex_par:gsub(replace_pattern, "-jobname=".. slug)
  else
    return latex_par .. "-jobname="..slug
  end
end

-- execute the function passed as parameter only once, when the file matching
-- starts
local function insert_filter(make, pattern, fn)
  local insert_executed = false
  table.insert(make.matches, 1, {
    pattern=pattern,
    params = make.params or {},
    command = function()
      if not insert_executed  then
        fn()
      end
      insert_executed = true
    end
  })
end

local function remove_maketitle(make)
  -- use DOM filter to remove \maketitle block
  local domfilter = require "make4ht-domfilter"
  local process = domfilter({
    function(dom)
      local maketitles = dom:query_selector(".maketitle")
      for _, el in ipairs(maketitles) do
        log:debug("removing maketitle")
        el:remove_node()
      end
      return dom
    end
  }, "staticsite")
  make:match("html$", process)
end


local function copy_files(filename, par)
  local function prepare_path(dir, subdir)
    local f = filename
    if par.builddir then
        f = f:gsub("^" .. par.builddir .. "/", "")
    end
    local path = dir .. "/" .. subdir .. "/" .. f
    return path:gsub("//", "/")
  end
  -- get extension settings
  local site_settings = get_filter_settings "staticsite"
  local site_root = site_settings.site_root or par.outdir 
  if site_root == "" then site_root = "./" end
  local map = site_settings.map or {}
  -- default path without subdir, will be used if the file is not matched
  -- by any pattern in the map
  local path = prepare_path(site_root, "")
  for pattern, destination in pairs(map) do
    if filename:match(pattern) then
      path = prepare_path(site_root, destination)
      break
    end
  end
  -- it is possible to use string extrapolation in path, for example for slug
  mkutils.copy(filename, path % par)
end

function M.modify_build(make)
  -- it is necessary to insert the filters for YAML header and file copying as last matches
  -- we use an bogus match which will be executed only once as the very first one to insert
  -- the filters
  -- I should make filter from this
  local process = filter({
    "staticsite"
  }, "staticsite")

  -- detect if we should remove maketitle
  local site_settings = get_filter_settings "staticsite"
  -- \maketitle is removed by default, set `remove_maketitle=false` setting to disable that
  if site_settings.remove_maketitle ~= false then
    remove_maketitle(make)
  end

  local settings = make.params
  -- get the published file name
  local slug = get_slug(settings)
  for _, cmd in ipairs(make.build_seq) do
    -- all commands must use the published file name
    cmd.params.input = slug
    cmd.params.latex_par = update_jobname(slug, cmd.params.latex_par)
  end

  local quotepattern = '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])'
  local mainfile = string.gsub(slug, quotepattern, "%%%1")

  -- run the following code once in the first match on the first file
  insert_filter(make, ".*", function()
    -- for _, match in ipairs(make.matches) do
    --   match.params.outdir = outdir
    --   print(match.pattern, match.params.outdir)
    -- end
    local params = make.params
    params.slug = slug
    make:match("html?$", process, params)
    make:match(".*", copy_files, params)
  end)

  return make
end

return M