-- TODO
-- reuse existing split
-- use fqcn as buffer name
-- add function to convert to fqcn, with telescope dropdown if there are multiple options
-- telescope window to search through all available module names, enter inserts, other key opens doc in split


local ts = require('nvim-treesitter.parsers')

local M = {}

M.example = function()
    local bufnr = vim.api.nvim_get_current_buf()
    local file_basename = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr), ':t')
    local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
    local parser = ts.get_parser(bufnr, 'yaml')
    local tree = parser:parse()[1]
    local root = tree:root()

    local objects = {}

    local current_line_nr = 1
    while current_line_nr <= #lines do
        local line = lines[current_line_nr]

        -- print('current_line_nr', current_line_nr)
        -- print('line', line)

        if not line or line:match("^%s*$") then
            -- print('empty line, continuing')
            current_line_nr = current_line_nr + 1
            goto continue
        end

        -- if line:match("^%s*#") then
        --     -- print('comment, continuing')
        --     -- todo - how? they are currently part of the nodes, but the previous one - if anything i want them to stick to the next one
        --     current_line_nr = current_line_nr + 1
        --     goto continue
        -- end

        local node = root:named_descendant_for_range(current_line_nr-1, 0, current_line_nr-1, #line)
        if node and (node:type() == 'block_mapping_pair') then
            -- local node_lines = vim.treesitter.get_node_text(node, bufnr) -- not using, returns string, we want a table
            local start_row, _, end_row, _ = node:range()
            local node_lines = vim.api.nvim_buf_get_lines(bufnr, start_row, end_row + 1, false)
            -- print('line', line)
            -- print('node type', node:type())
            -- print('node range', node:range())
            -- print('node lines', node_lines)

            table.insert(objects, {
                sort_line = line,
                lines = node_lines,
            })
            -- set current line to the next line after the node's end, and accouting for 0-indexing
            current_line_nr = end_row + 2
            goto continue
        end

        -- do not get stuck on lines that do not match above
        print('did not match the line, node type: ', node:type(), ', line: ', line)
        -- insert it anyway, we do not want to loose lines
        table.insert(objects, {
            sort_line = line,
            lines = {line},
        })
        current_line_nr = current_line_nr + 1
        ::continue::
    end

    -- print(vim.inspect(objects))
    table.sort(
        objects,
        function(k1, k2)
            return k1.sort_line < k2.sort_line
        end
    )
    -- print(vim.inspect(objects))

    -- clear the buffer
    vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {})

    -- flatten sorted objects into lines and insert back into the buffer
    local sorted_lines = {}
    local last_prefix = nil
    for _, obj in ipairs(objects) do

        -- if the prefix switches, insert an empty line before the lines
        local split_line = vim.split(obj.sort_line, '__')
        -- if we only get one element back this means the line does not contain '__'
        -- lets try splitting on '_'
        -- else the fallback is the whole line
        if #split_line <= 1 then
            split_line = vim.split(obj.sort_line, '_')
        end
        local current_prefix = split_line[1]
        -- special case for hosts.yml
        if file_basename == 'hosts.yml' then
            current_prefix = obj.sort_line
        end
        -- print('current_prefix', current_prefix)
        -- print('last_prefix', last_prefix)

        if last_prefix == nil then
            -- handle the first line
            last_prefix = current_prefix

        elseif current_prefix ~= last_prefix then
            -- print('inserting newline')
            table.insert(sorted_lines, "")
            last_prefix = current_prefix
        end

        -- print('obj', vim.inspect(obj))

        for _, line in ipairs(obj.lines) do
            table.insert(sorted_lines, line)
        end
    end

    -- print('sorted_lines', vim.inspect(sorted_lines))
    vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, sorted_lines)
end


M.display_ansible_doc = function(keyword)

    local Job = require'plenary.job'

    -- local keyword = 'get_url'
    local doc = {}

    Job:new({
        command = 'ansible-doc',
        args = { keyword },
        on_exit = function(j, return_val)
            -- print(return_val)
            -- print(vim.inspect(j:result()))
            doc = j:result()
        end,
    }):sync() -- or start()

    -- TODO unlisted / scratch buffer?
    local fqcn = string.lower(vim.split(doc[1], ' ')[2])

    vim.api.nvim_command('vsplit ' .. fqcn)

    local win_handle = vim.api.nvim_tabpage_get_win(0)
    local buf_handle = vim.api.nvim_win_get_buf(0)

    vim.api.nvim_buf_set_lines(buf_handle, 0, -1, false, doc)

    vim.api.nvim_buf_set_option(buf_handle, 'readonly', true)
    vim.api.nvim_buf_set_option(buf_handle, 'modifiable', false)

    -- Now we set some options for our buffer.
    -- nofile prevent mark buffer as modified so we never get warnings about not saved changes.
    -- Also some plugins treat nofile buffers different.
    -- For example coc.nvim don't triggers aoutcompletation for these.
    vim.api.nvim_buf_set_option(buf_handle, 'buftype', 'nofile')
    -- We do not need swapfile for this buffer.
    vim.api.nvim_buf_set_option(buf_handle, 'swapfile', false)
    -- And we would rather prefer that this buffer will be destroyed when hide.
    vim.api.nvim_buf_set_option(buf_handle, 'bufhidden', 'wipe')
    -- It's not necessary but it is good practice to set custom filetype.
    -- This allows users to create their own autocommand or colorschemes on filetype.
    -- and prevent collisions with other plugins.
    vim.api.nvim_buf_set_option(buf_handle, 'filetype', 'ansible-doc')

    -- vim.api.nvim_command('wincmd p') -- go back to previous window
end


M.replace_fqcn = function()

    local Job = require'plenary.job'

    -- keyword = 'get_url'
    doc = {}

    Job:new({
        command = 'ansible-doc',
        args = { keyword },
        on_exit = function(j, return_val)
            -- print(return_val)
            -- print(vim.inspect(j:result()))
            doc = j:result()
        end,
    }):sync() -- or start()

    fqcn = string.lower(vim.split(doc[1], ' ')[2])
    cur_pos = vim.api.nvim_win_get_cursor(0)

    buf_handle = vim.api.nvim_win_get_buf(0)
    vim.api.nvim_buf_set_lines(buf_handle, 0, -1, false, doc)

end

return M