local function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

local augroup = vim.api.nvim_create_augroup("Timer", { clear = true })
local filename = ".timer.toml"
local username = trim(os.getenv("USER")) .. "_at_" .. trim(io.popen("hostname -s"):read("*a"))
local focus_events = {}
local clean_to = 1



local function clean_from(from, events)
  local clean_events = {}

  -- coppy until from
  for i = 1, from - 1, 1 do
    table.insert(clean_events, events[i])
  end

  local last = {}
  for i = from, #events, 1
  do
    local event = events[i]
    local next_event = events[i + 1]


    if next_event == nil then
      --do nothing
    elseif next_event.event == "gain" and event.event == "lose" then
      if os.difftime(next_event.time, event.time) > 5 * 60 then
        table.insert(clean_events, event)
      end
    end
    if last == nil then
      -- do nothing
    elseif last.event == "lose" and event.event == "gain" then
      if os.difftime(event.time, last.time) > 5 * 60 then
        table.insert(clean_events, event)
      end
    end

    last = event
  end

  return clean_events
end

local function summ_time()
  focus_events = clean_from(clean_to + 1, focus_events)
  clean_to = #focus_events

  local t = 0

  local start = os.time()
  for _, fe in pairs(focus_events) do
    if fe.event == "gain" then
      start = fe.time
    else
      t = t + os.difftime(fe.time, start)
    end
    if focus_events[#focus_events].event == "gain" then
      t = t + os.difftime(os.time(), focus_events[#focus_events].time)
    end
  end
  return t
end

local function fmt_time(time)
  local str = ""

  local days = math.floor(time / (60 * 60 * 24))
  if days ~= 0 then
    str = str .. days .. "d"
  end

  time = time % (60 * 60 * 24)

  local hours = math.floor(time / (60 * 60))
  if hours ~= 0 then
    str = str .. hours .. "h"
  end

  time = time % (60 * 60)

  local minutes = math.floor(time / 60)
  if minutes ~= 0 then
    str = str .. minutes .. "m"
  end

  local seconds = time % (60)
  if seconds ~= 0 then
    str = str .. seconds .. "s"
  end

  return str
end

local function log_total_time()
  local times = {}
  times[username] = summ_time()

  local file = io.open(filename, "r")

  -- if file exists read
  if file ~= nil then
    local history = require("toml").parse(file:read("*a"))
    file:close()

    print("Time for:", filename)

    for _, day in pairs(history) do
      for user, time in pairs(day) do
        if times[user] == nil then
          times[user] = 0
        end
        times[user] = times[user] + time
      end
    end
  end

  for user, time in pairs(times) do
    print(user, fmt_time(time))
  end
end


local function log_time_table()
  for i, e in pairs(focus_events) do
    print(i, e.event, os.date("%H:%M:%S", e.time))
  end
end

local function focus_gained()
  table.insert(focus_events, {
    time = os.time(),
    event = "gain",
  })
end

local function focus_lost()
  table.insert(focus_events, {
    time = os.time(),
    event = "lose",
  })
end

local function next_lowest_time_file()
  local file_path = filename

  for _ = 1, 10, 1 do
    local f = io.open(file_path)

    if f ~= nil then
      return file_path
    end

    file_path = "../" .. file_path
  end

  return ""
end

local function persist(force)
  return function()
    local TOML = require("toml")
    local today = os.date("%y-%m-%d", os.time())
    local table = {}
    local file_path = filename

    local file = io.open(file_path, "r")
    -- if file exists read
    if file ~= nil then
      table = TOML.parse(file:read("*a"))
      file:close()
    else
      if not force then
        file_path = next_lowest_time_file()
        if file_path == "" then
          print("No save file found. To create a new save file run :TimerSave")
          return
        end
        print("Save file found:", file_path)
      end
    end

    -- write time to table
    if table[today] ~= nil and table[today][username] ~= nil then
      table[today][username] = table[today][username] + summ_time()
    else
      if table[today] == nil then
        table[today] = {}
      end
      table[today][username] = summ_time()
    end

    -- write table to file
    file = io.open(file_path, "w")
    if file == nil then
      error("can't write to .timer file")
      return
    end

    local tml = TOML.encode(table)

    file:write("## dates and their corresponding seconds been here :)\n", tml, "\n")
    file:close()

    print("Timer saved successfully :-)")

    --reset timer
    clean_to = 1
    focus_events = {}
    focus_gained()
  end
end

local function setup()
  vim.api.nvim_create_autocmd("VimEnter",
    { group = augroup, desc = "Start Timer", once = true, callback = focus_gained })
  vim.api.nvim_create_autocmd("ExitPre",
    { group = augroup, desc = "Persist timer", once = true, callback = persist(false) })
  vim.api.nvim_create_autocmd("FocusGained", { group = augroup, callback = focus_gained })
  vim.api.nvim_create_autocmd("FocusLost", { group = augroup, callback = focus_lost })

  vim.api.nvim_create_user_command(
    'Timer',
    log_total_time,
    { nargs = 0 } -- No arguments for this command (you can configure this later)
  )
  vim.api.nvim_create_user_command(
    'TimerLog',
    log_time_table,
    { nargs = 0 } -- No arguments for this command (you can configure this later)
  )
  vim.api.nvim_create_user_command(
    'TimerSave',
    persist(true),
    { nargs = 0 } -- No arguments for this command (you can configure this later)
  )
end

return { setup = setup }