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

-- Custom previewer that dynamically calculates how many lines
-- can fit in the preview window, then shows a centered slice.
local dynamic_previewer = previewers.new_buffer_previewer({
  define_preview = function(self, entry, status)
    -- 'entry.lnum' is the *actual file line number*.
    local filepath = entry.path
    local target   = entry.lnum or 1

    -- Get the preview buffer & window
    local pbufnr = self.state.bufnr
    local pwinid = status.preview_win
    if not pbufnr or not vim.api.nvim_buf_is_valid(pbufnr) then
      return
    end
    if not pwinid or not vim.api.nvim_win_is_valid(pwinid) then
      return
    end

    -- How many lines can we show in the preview window?
    -- Subtract a bit (e.g., 1 or 2) if you use borders or want extra margin.
    local lines_in_window = vim.api.nvim_win_get_height(pwinid) - 1
    if lines_in_window < 1 then
      lines_in_window = 1
    end

    -- Read the entire file, figure out the slice to show
    local all_lines = vim.fn.readfile(filepath)
    local total = #all_lines

    -- We'll center on the target line, if possible
    local half_context = math.floor(lines_in_window / 2)
    local start_line = math.max(target - half_context, 1)
    local end_line = math.min(start_line + lines_in_window - 1, total)

    -- Collect that slice of lines
    local preview_lines = {}
    for i = start_line, end_line do
      table.insert(preview_lines, all_lines[i])
    end

    -- Write the slice to the preview buffer
    vim.api.nvim_buf_set_lines(pbufnr, 0, -1, false, preview_lines)
    vim.api.nvim_buf_clear_namespace(pbufnr, -1, 0, -1)

    -- Highlight the target line within the slice
    local relative_line = target - start_line + 1
    if relative_line >= 1 and relative_line <= #preview_lines then
      vim.api.nvim_buf_add_highlight(
        pbufnr, -1, "Search", relative_line - 1, 0, -1
      )
    end
  end,
})

local function jump_to_line()
  local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
  local current_file = vim.api.nvim_buf_get_name(0)
  local entries = {}

  for i, text in ipairs(lines) do
    table.insert(entries, {
      value   = text,
      display = string.format("%d: %s", i, text),
      ordinal = text,
      path    = current_file, -- needed by the previewer
      lnum    = i,            -- actual file line number
    })
  end

  pickers.new({}, {
    prompt_title = "Jump to Line",
    finder = finders.new_table({
      results = entries,
      entry_maker = function(e) return e end,
    }),
    sorter = conf.generic_sorter({}),
    previewer = dynamic_previewer,
    attach_mappings = function(prompt_bufnr, _)
      actions.select_default:replace(function()
        actions.close(prompt_bufnr)
        local selection = action_state.get_selected_entry()
        if selection then
          local target_line = selection.lnum
          local closed_line = vim.fn.foldclosed(target_line)
          if closed_line ~= -1 then
            target_line = closed_line
          end
          -- Jump and open the fold
          vim.cmd(string.format("normal! %dG", target_line))
          vim.cmd("normal! zv")
        end
      end)
      return true
    end,
  }):find()
end

return { jump_to_line = jump_to_line }
