local Trans = require('Trans')

-- FIXME :Adjust Window Size

---@class TransHover: TransFrontend
---@field ns integer @namespace for hover window
---@field buffer TransBuffer @buffer for hover window
---@field window TransWindow @hover window
---@field queue TransHover[] @hover queue for all hover instances
---@field destroy_funcs fun(hover:TransHover)[] @functions to be executed when hover window is closed
---@field opts TransHoverOpts @options for hover window
---@field pin boolean @whether hover window is pinned
local M = Trans.metatable('frontend.hover', {
    ns    = vim.api.nvim_create_namespace('TransHoverWin'),
    queue = {},
})
M.__index = M

---Create a new hover instance
---@return TransHover new_instance
function M.new()
    local new_instance = {
        pin = false,
        buffer = Trans.buffer.new(),
        destroy_funcs = {},
    }
    M.queue[#M.queue + 1] = new_instance

    return setmetatable(new_instance, M)
end

---Get the first active instances
---@return TransHover
function M.get_active_instance()
    M.clear_dead_instance()
    return M.queue[1]
end

---Clear dead instance
function M.clear_dead_instance()
    local queue = M.queue
    for i = #queue, 1, -1 do
        if not queue[i]:is_available() then
            queue[i]:destroy()
            table.remove(queue, i)
        end
    end
end

---Destroy hover instance and execute destroy functions
function M:destroy()
    coroutine.wrap(function()
        for _, func in ipairs(self.destroy_funcs) do
            func(self)
        end


        if self.window:is_valid() then self.window:try_close() end
        if self.buffer:is_valid() then self.buffer:destroy() end
        self.pin = false
    end)()
end

---Init hover window
---@param opts?
---|{width?: integer, height?: integer, col?: integer, row?: integer, relative?: string}
---@return unknown
function M:init_window(opts)
    opts           = opts or {}
    local m_opts   = self.opts
    local option   = {
        ns        = self.ns,
        buffer    = self.buffer,
        animation = m_opts.animation,
    }

    local win_opts = {
        col      = opts.col or 1,
        row      = opts.row or 1,
        title    = m_opts.title,
        relative = opts.relative or 'cursor',
        width    = opts.width or m_opts.width,
        height   = opts.height or m_opts.height,
    }

    if win_opts.title then
        win_opts.title_pos = 'center'
    end

    option.win_opts = win_opts
    self.window = Trans.window.new(option)
    return self.window
end

---Wait for data
---@param tbl table @table to be checked
---@param name string @key to be checked
---@param timeout number @timeout for waiting
function M:wait(tbl, name, timeout)
    local opts    = self.opts
    local width   = opts.width
    local spinner = Trans.style.spinner[self.opts.spinner]
    local size    = #spinner
    local cell    = self.opts.icon.cell

    local function update_text(times)
        return spinner[times % size + 1] .. (cell):rep(times)
    end


    self:init_window({
        height = 1,
        width = width,
    })


    local interval = math.floor(timeout / width)
    local pause = Trans.util.pause
    local buffer = self.buffer
    for i = 1, width do
        if tbl[name] ~= nil then break end
        buffer[1] = update_text(i)
        buffer:add_highlight(1, 'MoreMsg')
        pause(interval)
    end


    -- FIXME :
    -- buffer:wipe()
    -- vim.api.nvim_buf_set_lines(buffer.bufnr, 1, -1, true, {})
    -- print('jklajsdk')
    -- print(vim.fn.deletebufline(buffer.bufnr, 1))
    -- buffer:del()
    buffer[1] = ''
end

---Display Result in hover window
---@param data TransData
---@param result TransResult
---@overload fun(result:TransResult)
function M:process(data, result)
    -- local node = Trans.util.node
    -- local it, t, f = node.item, node.text, node.format
    -- self.buffer:setline(it('hello', 'MoreMsg'))
    local opts = self.opts
    if not self.buffer:is_valid() then self.buffer:init() end

    if opts.auto_play then
        (data.from == 'en' and data.str or result.definition[1]):play()
    end

    for _, field in ipairs(opts.order) do
        if result[field] then
            self:load(result, field)
        end
    end

    local window = self.window
    local display_size = Trans.util.display_size(self.buffer:lines(), opts.width)
    if window and window:is_valid() then
        if opts.auto_resize then
            display_size.width = math.min(opts.width, display_size.width + opts.padding)
        else
            display_size.width = nil
        end
        window:resize(display_size)
    else
        window = self:init_window {
            height = math.min(opts.height, display_size.height),
            width = math.min(opts.width, display_size.width + opts.padding),
        }
    end

    window:set('wrap', true)


    local auto_close_events = opts.auto_close_events
    if auto_close_events then
        vim.api.nvim_create_autocmd(auto_close_events, {
            once = true,
            callback = function()
                if self.pin then return end
                self:destroy()
            end,
        })
    end

    -- vim.api.nvim_create_autocmd('User', {
    --     pattern = 'TransHoverReady',
    --     callback = function(opts)
    --         vim.print(opts)
    --         ---@type TransHover
    --         local hover = opts.data
    --     end,
    --     desc = 'Auto Close Hover Window',
    -- })

    -- vim.api.nvim_exec_autocmds('User', {
    --     pattern = 'TransHoverReady',
    --     data = self,
    -- })
end

---Check if hover window and buffer are valid
---@return boolean @whether hover window and buffer are valid
function M:is_available()
    return self.buffer:is_valid() and self.window:is_valid()
end

---@class TransFrontend
---@field hover TransHover @hover frontend
return M
--     local cmd_id
--     local next
--     local action = {
--         pageup = function()
--             buffer:normal('gg')
--         end,

--         pagedown = function()
--             buffer:normal('G')
--         end,

--         pin = function()
--             if lock then
--                 error('请先关闭窗口')
--             else
--                 lock = true
--             end
--             pcall(api.nvim_del_autocmd, cmd_id)
--             local width, height = win.width, win.height
--             local col = vim.o.columns - width - 3
--             local buf = buffer.bufnr
--             local run = win:try_close()
--             run(function()
--                 local w, r = open_window {
--                     width = width,
--                     height = height,
--                     relative = 'editor',
--                     col = col,
--                 }

--                 next = w.winid
--                 win = w
--                 r(function()
--                     w:set('wrap', true)
--                 end)

--                 del('n', keymap.pin)
--                 api.nvim_create_autocmd('BufWipeOut', {
--                     callback = function(opt)
--                         if opt.buf == buf or opt.buf == cur_buf then
--                             lock = false
--                             api.nvim_del_autocmd(opt.id)
--                         end
--                     end
--                 })
--             end)
--         end,

--         close = function()
--             pcall(api.nvim_del_autocmd, cmd_id)
--             local run = win:try_close()
--             run(function()
--                 buffer:delete()
--             end)
--             try_del_keymap()
--         end,

--         toggle_entry = function()
--             if lock and win:is_valid() then
--                 local prev = api.nvim_get_current_win()
--                 api.nvim_set_current_win(next)
--                 next = prev
--             else
--                 del('n', keymap.toggle_entry)
--             end
--         end,

--         play = function()
--             if word then
--                 word:play()
--             end
--         end,
--     }
--     local set = vim.keymap.set
--     for act, key in pairs(hover.keymap) do
--         set('n', key, action[act])
--     end


--     if hover.auto_close_events then
--         cmd_id = api.nvim_create_autocmd(
--             hover.auto_close_events, {
--             buffer = 0,
--             callback = action.close,
--         })
--     end
-- end