local action_state = require("telescope.actions.state")
local actions = require("telescope.actions")
local finders = require("telescope.finders")
local pickers = require("telescope.pickers")
local previewers = require("telescope.previewers")
local telescope = require("telescope")
local conf = require("telescope.config").values
local entry_display = require("telescope.pickers.entry_display")

local function parse_links(bufnr)
  local links = {}
  local lines = vim.api.nvim_buf_get_lines(bufnr or 0, 0, -1, false)

  for lnum, line in ipairs(lines) do
    -- Parse wikilinks [[link]]
    for link in line:gmatch("%[%[([^%]]+)%]%]") do
      table.insert(links, {
        link = link,
        line = lnum,
        col = line:find("%[%[" .. vim.pesc(link)),
        type = "wikilink",
        text = line,
      })
    end

    -- Parse markdown links [text](link)
    for text, link in line:gmatch("%[([^%]]+)%]%(([^%)]+)%)") do
      table.insert(links, {
        link = link,
        text = text,
        line = lnum,
        col = line:find("%[" .. vim.pesc(text)),
        type = "markdown",
        text_line = line,
      })
    end

    -- Parse autolinks <link>
    for link in line:gmatch("<([^>]+)>") do
      table.insert(links, {
        link = link,
        line = lnum,
        col = line:find("<" .. vim.pesc(link)),
        type = "autolink",
        text = line,
      })
    end
  end

  return links
end

local function markdown_links_picker(opts)
  opts = opts or {}
  local bufnr = vim.api.nvim_get_current_buf()
  local links = parse_links(bufnr)

  if #links == 0 then
    vim.notify("No links found in current buffer", vim.log.levels.INFO)
    return
  end

  local displayer = entry_display.create({
    separator = " ",
    items = {
      { width = 10 },
      { width = 8 },
      { remaining = true },
    },
  })

  local make_display = function(entry)
    return displayer({
      { entry.line .. ":" .. entry.col, "TelescopeResultsLineNr" },
      { entry.type, "TelescopeResultsIdentifier" },
      { entry.link, "TelescopeResultsString" },
    })
  end

  pickers
    .new(opts, {
      prompt_title = "Links in Buffer",
      finder = finders.new_table({
        results = links,
        entry_maker = function(entry)
          return {
            value = entry,
            display = make_display,
            ordinal = entry.link .. " " .. entry.text,
            link = entry.link,
            line = entry.line,
            col = entry.col,
            type = entry.type,
          }
        end,
      }),
      sorter = conf.generic_sorter(opts),
      previewer = previewers.new_buffer_previewer({
        define_preview = function(self, entry, status)
          local preview_bufnr = self.state.bufnr
          vim.api.nvim_buf_set_lines(preview_bufnr, 0, -1, false, { entry.value.text })
          vim.api.nvim_buf_add_highlight(preview_bufnr, -1, "Search", 0, 0, -1)
        end,
      }),
      attach_mappings = function(prompt_bufnr, map)
        actions.select_default:replace(function()
          actions.close(prompt_bufnr)
          local selection = action_state.get_selected_entry()
          if selection then
            vim.api.nvim_win_set_cursor(0, { selection.line, selection.col - 1 })
            vim.cmd("normal! zz")
          end
        end)
        return true
      end,
    })
    :find()
end

return markdown_links_picker
