local awful = require('awful')
local naughty = require('naughty')
local wibox = require('wibox')
local gears = require('gears')
local beautiful = require('beautiful')

local dpi = require('beautiful').xresources.apply_dpi

local HOME = os.getenv('HOME')
local PATH_TO_ICONS = HOME .. '/.config/awesome/notif-center/icons/'

-- Boolean variable to remove empty message
local remove_notifbox_empty = true

-- Notification boxes container layout
local notifbox_layout = wibox.layout.fixed.vertical()

-- Notification boxes container layout spacing
notifbox_layout.spacing = dpi(5)

notifbox_layout.expand = 'none'

-- Notification icon container
local notifbox_icon = function(ico_image)
  local noti_icon = wibox.widget {
    {
      id = 'icon',
      resize = true,
      forced_height = dpi(25),
      forced_width = dpi(25),
      widget = wibox.widget.imagebox
    },
    layout = wibox.layout.fixed.horizontal
  }
  noti_icon.icon:set_image(ico_image)
  return noti_icon
end

-- Notification title container
local notifbox_title = function(title)
  return wibox.widget {
    text   = title,
    font   = 'SFNS Display Bold 12',
    align  = 'left',
    valign = 'center',
    widget = wibox.widget.textbox
  }
end

-- Notification message container
local notifbox_message = function(msg)
  return wibox.widget {
    text   = msg,
    font   = 'SFNS Display Regular 11',
    align  = 'left',
    valign = 'center',
    widget = wibox.widget.textbox
  }
end

-- Notification app name container
local notifbox_appname = function(app)
  return wibox.widget {
    text   = app,
    font   = 'SFNS Display Bold 12',
    align  = 'left',
    valign = 'center',
    widget = wibox.widget.textbox
  }
end

-- Get current time
local current_time = function()
  return os.date("%H:%M:%S")
end

-- Convert time to seconds
local parse_to_seconds = function(time)
  -- Convert HH in HH:MM:SS
  hourInSec = tonumber(string.sub(time, 1, 2)) * 3600

  -- Convert MM in HH:MM:SS
  minInSec = tonumber(string.sub(time, 4, 5)) * 60

  -- Get SS in HH:MM:SS
  getSec = tonumber(string.sub(time, 7, 8))

  return (hourInSec + minInSec + getSec)

end


-- Notification actions container
local notifbox_actions = function(notif)
  actions_template = wibox.widget {
    notification = notif,
    base_layout = wibox.widget {
      spacing        = dpi(5),
      layout         = wibox.layout.flex.vertical
    },
    widget_template = {
      {
        {
          {
            id     = 'text_role',
            font   = 'SFNS Display Regular 10',
            widget = wibox.widget.textbox
          },
            widget = wibox.container.place
        },
        bg                 = beautiful.bg_actions,
        shape              = gears.shape.rounded_rect,
        forced_height      = 30,
        widget             = wibox.container.background,
      },
      margins = 4,
      widget  = wibox.container.margin,
    },
    style = { underline_normal = false, underline_selected = true },
    widget = naughty.list.actions,
  }

  return actions_template
end

-- Empty notification message
local notifbox_empty = function()
  local empty_notifbox = wibox.widget {
    {
      layout = wibox.layout.fixed.vertical,
      spacing = dpi(5),
      {
        expand = 'none',
        layout = wibox.layout.align.horizontal,
        nil, 
        {
          image = PATH_TO_ICONS .. 'empty-notification' .. '.svg',
          resize = true,
          forced_height = dpi(35),
          forced_width = dpi(35),
          widget = wibox.widget.imagebox,
        },
        nil
      },
      {
        text = 'Wow, such empty.',
        font = 'SFNS Display Bold 14',
        align = 'center',
        valign = 'center',
        widget = wibox.widget.textbox
      },
      {
        text = 'Come back later.',
        font = 'SFNS Display Regular 10',
        align = 'center',
        valign = 'center',
        widget = wibox.widget.textbox
      },
    },
    margins = dpi(20),
    widget = wibox.container.margin
    
  }


  local separator_for_empty_msg =  wibox.widget
  {
    orientation = 'vertical',
    opacity = 0.0,
    widget = wibox.widget.separator
  }

  -- Make empty_notifbox center
  local centered_empty_notifbox = wibox.widget {
    expand = 'none',
    layout = wibox.layout.align.vertical,
    separator_for_empty_msg,
    empty_notifbox,
    separator_for_empty_msg
  }

  return centered_empty_notifbox
end

-- Reset notifbox_layout
reset_notifbox_layout = function()
  notifbox_layout:reset(notifbox_layout)
  notifbox_layout:insert(1, notifbox_empty())
  remove_notifbox_empty = true
end

-- Returns the notification box
local notifbox_box = function(notif, icon, title, message, app, bgcolor)

  -- Get current time for `this` instance of box
  local time_of_pop = current_time()
  
  -- Notification time pop container
  local notifbox_timepop =  wibox.widget {
    id = 'time_pop',
    text = nil,
    font = 'SFNS Display Regular 10',
    align = 'left',
    valign = 'center',
    widget = wibox.widget.textbox
  }

  -- Timer for notification time pop
  gears.timer {
    timeout   = 60,
    call_now  = true,
    autostart = true,
    callback  = function()

      local time_difference = nil
      -- Get the time difference
      time_difference = parse_to_seconds(current_time()) - parse_to_seconds(time_of_pop)
      -- String to Number
      time_difference = tonumber(time_difference)

      -- If seconds is less than one minute
      if time_difference < 60 then
        notifbox_timepop.text = 'now'

      -- If greater that one hour
      elseif time_difference >= 3600 then
        notifbox_timepop.text = time_of_pop

      -- Use time of popup instead
      else
        local time_in_minutes = math.floor(time_difference / 60)
        if tonumber(time_in_minutes) > 1 then
          notifbox_timepop.text = time_in_minutes .. ' ' .. 'minutes ago'
        else
          notifbox_timepop.text = time_in_minutes .. ' ' .. 'minute ago'
        end
      end

      collectgarbage('collect')
    end
  }

  -- Template of notification box
  local notifbox_template =  wibox.widget {
    id = 'notifbox_template',
    expand = 'none',
    {
      {
        layout = wibox.layout.fixed.vertical,
        spacing = dpi(5),
        {
          expand = 'none',
          layout = wibox.layout.align.horizontal,
          {
            layout = wibox.layout.fixed.horizontal,
            spacing = dpi(5),
            notifbox_icon(icon),
            notifbox_appname(app),
          },
          nil,
          notifbox_timepop
        },
        {
          layout = wibox.layout.fixed.vertical,
          spacing = dpi(5),
          {
            notifbox_title(title),
            notifbox_message(message),
            layout = wibox.layout.fixed.vertical
          },
          notifbox_actions(notif),
        },

      },
      margins = dpi(10),
      widget = wibox.container.margin
    },
    bg = bgcolor,
    shape = function(cr, width, height)
      gears.shape.partially_rounded_rect(cr, width, height, true, true, true, true, beautiful.modal_radius) end,
    widget = wibox.container.background,
  }

  -- Delete notification box
  local notifbox_delete = function()
    notifbox_layout:remove_widgets(notifbox_template, true)
  end

  -- Delete notification box when pressed
  notifbox_template:connect_signal("button::press", function(_, _, _, button)
    if #notifbox_layout.children == 1 then
      reset_notifbox_layout()
    else
      notifbox_delete()
    end
  end)

  return notifbox_template
end


-- Add empty notification message on start-up
notifbox_layout:insert(1, notifbox_empty())

-- Connect to naughty
naughty.connect_signal("request::display", function(n)

  -- If notifbox_layout has a child and remove_notifbox_empty
  if #notifbox_layout.children == 1 and remove_notifbox_empty then
    -- Reset layout
    notifbox_layout:reset(notifbox_layout)
    remove_notifbox_empty = false
  end


  -- Set background color based on urgency level
  local notifbox_color = beautiful.bg_modal
  if n.urgency == 'critical' then
    notifbox_color = n.bg .. '66'
  end

  -- Check if there's an icon
  local appicon = n.icon
  if not appicon then
    appicon = PATH_TO_ICONS .. 'new-notif' .. '.svg'
  end

  -- Throw data from naughty to notifbox_layout 
  -- Generates notifbox
  notifbox_layout:insert(1, 
    notifbox_box(
      n, 
      appicon, 
      n.title, 
      n.message, 
      n.app_name, 
      notifbox_color)
    )


end)


return notifbox_layout