local base = require("wibox.widget.base")
local gtable = require("gears.table")
local gcolor = require("gears.color")
local dpi = require("beautiful").xresources.apply_dpi
local wibox = require("wibox")
local gshape = require("gears.shape")
local rubato = require("src.lib.rubato")
local abutton = require("awful.button")

local toggle_widget = { mt = {} }

function toggle_widget:layout(_, width, height)
  if self._private.widget then
    return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
  end
end

function toggle_widget:fit(context, width, height)
  local w, h = 0, 0
  if self._private.widget then
    w, h = base.fit_widget(self, context, self._private.widget, width, height)
  end
  return w, h
end

toggle_widget.set_widget = base.set_widget_common

function toggle_widget:get_widget()
  return self._private.widget
end

function toggle_widget:set_enabled()
  self.active = true
  self.toggle_button.border_color = self.color
  self.newcolor = self.color
  self.rubato_timed.target = 39
end

function toggle_widget:set_disabled()
  self.active = not self.active
  self.toggle_button.border_color = Theme_config.dnd.border_disabled
  self.newcolor = Theme_config.dnd.disabled
  self.rubato_timed.target = 5
end

function toggle_widget:toggle_animation(pos, color)
  if pos > 39 then return end
  return function(_, _, cr, width, height)
    cr:set_source(gcolor(Theme_config.dnd.bg))
    cr:paint()
    cr:set_source(gcolor(color))
    cr:move_to(pos, 0)
    local x = pos
    local y = 5
    local newwidth = width / 2 - 10
    local newheight = height - 10

    local radius = height / 6.0
    local degrees = math.pi / 180.0

    cr:new_sub_path()
    cr:arc(x + newwidth - radius, y + radius, radius, -90 * degrees, 0 * degrees)
    cr:arc(x + newwidth - radius, y + newheight - radius, radius, 0 * degrees, 90 * degrees)
    cr:arc(x + radius, y + newheight - radius, radius, 90 * degrees, 180 * degrees)
    cr:arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees)
    cr:close_path()
    cr:fill()
  end
end

function toggle_widget.new(args)
  args = args or {}

  local ret = base.make_widget(nil, nil, {
    enable_properties = true,
  })

  gtable.crush(ret, toggle_widget, true)

  ret.newcolor = Theme_config.dnd.disabled
  ret.color = args.color

  ret.toggle_button = wibox.widget {
    {
      widget = wibox.widget {
        fit = function(_, width, height)
          return width, height
        end,
        draw = ret:toggle_animation(0, ret.newcolor),
      },
      id = "background",
    },
    active = false,
    widget = wibox.container.background,
    bg = Theme_config.dnd.bg,
    border_color = Theme_config.dnd.border_disabled,
    border_width = dpi(2),
    forced_height = args.size,
    forced_width = args.size * 2,
    shape = function(cr, width, height)
      gshape.rounded_rect(cr, width, height, dpi(10))
    end,
  }

  ret.rubato_timed = rubato.timed {
    duration = 0.2,
    pos = 5,
    subscribed = function(pos)
      ret.toggle_button:get_children_by_id("background")[1].draw = ret:toggle_animation(pos, ret.newcolor)
      ret.toggle_button:emit_signal("widget::redraw_needed")
    end
  }

  ret:set_widget(wibox.widget {
    {
      {
        args.text and {
          text = args.text,
          valign = "center",
          align = "center",
          widget = wibox.widget.textbox,
          id = "clearall"
        } or nil,
        ret.toggle_button,
        spacing = args.text and dpi(10) or dpi(0),
        layout = wibox.layout.fixed.horizontal,
        id = "layout12"
      },
      id = "background4",
      fg = args.fg,
      shape = function(cr, width, height)
        gshape.rounded_rect(cr, width, height, dpi(12))
      end,
      widget = wibox.container.background
    },
    id = "place",
    widget = wibox.container.place,
    valign = "bottom",
    halign = "right",
  })

  ret.toggle_button:buttons(
    gtable.join(
      abutton({}, 1, function()
        if ret.active then
          ret:set_disabled()
        else
          ret:set_enabled()
        end
        ret:emit_signal("dnd::toggle", ret.active)
      end
      )
    )
  )

  return ret
end

function toggle_widget.mt:__call(...)
  return toggle_widget.new(...)
end

return setmetatable(toggle_widget, toggle_widget.mt)
