-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
  local lazyrepo = "https://github.com/folke/lazy.nvim.git"
  local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
  if vim.v.shell_error ~= 0 then
    vim.api.nvim_echo({
      { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
      { out, "WarningMsg" },
      { "\nPress any key to exit..." },
    }, true, {})
    vim.fn.getchar()
    os.exit(1)
  end
end
vim.opt.rtp:prepend(lazypath)

-- Make sure to setup `mapleader` and `maplocalleader` before
-- loading lazy.nvim so that mappings are correct.
-- This is also a good place to setup other settings (vim.opt)
vim.g.mapleader = "'"
vim.g.maplocalleader = "\\"

-- Setup lazy.nvim
require("lazy").setup({
  spec = {
    -- import your plugins
    { import = "plugins" },
  },
  -- Configure any other settings here. See the documentation for more details.
  -- colorscheme that will be used when installing plugins.
   {colorscheme = "dracula"},
  -- automatically check for plugin updates
  checker = { enabled = true },
})
-- vim script 
vim.cmd[[colorscheme dracula]]
vim.cmd[[syntax enable]]
vim.cmd[[set number noswapfile hlsearch ignorecase incsearch cursorline]]
vim.cmd[[autocmd BufNewFile,BufRead ~/.config/waybar/config,*.json set ft=javascript]]
vim.cmd[[hi Normal guibg=NONE ctermbg=NONE]]
vim.cmd[[highlight CursorLine ctermbg=black]]
vim.cmd[[set noshowmode]]
-- lualine
require('lualine').setup {
  options = {
    icons_enabled = true,
    theme = 'dracula',
    component_separators = { left = '', right = ''},
    section_separators = { left = '', right = ''},
    disabled_filetypes = {
      statusline = {},
      winbar = {},
    },
    ignore_focus = {},
    always_divide_middle = true,
    always_show_tabline = true,
    globalstatus = false,
    refresh = {
      statusline = 100,
      tabline = 100,
      winbar = 100,
    }
  },
  sections = {
    lualine_a = {'mode'},
    lualine_b = {'branch', 'diff', 'diagnostics'},
    lualine_c = {'filename'},
    lualine_x = {'encoding', 'fileformat', 'filetype'},
    lualine_y = {'progress'},
    lualine_z = {'location'}
  },
  inactive_sections = {
    lualine_a = {},
    lualine_b = {},
    lualine_c = {'filename'},
    lualine_x = {'location'},
    lualine_y = {},
    lualine_z = {}
  },
  tabline = {
    lualine_a = {'buffers'},
    lualine_b = {'branch'},
    lualine_c = {'filename'},
    lualine_x = {},
    lualine_y = {},
    lualine_z = {'tabs'}
  },
  winbar = {},
  inactive_winbar = {},
  extensions = {}
}
-- mini.icons
require('mini.icons').setup()
-- plenary
local async = require "plenary.async"
-- yazi
require("yazi.commands").create_yazi_commands()
---@module "plenary"

local configModule = require("yazi.config")

local M = {}

M.version = "11.5.1" -- x-release-please-version

-- The last known state of yazi when it was closed
---@type YaziPreviousState
M.previous_state = {}

M.active_contexts = vim.ringbuf(2)

---@alias yazi.Arguments {reveal_path: string}

---@param config? YaziConfig | {}
---@param input_path? string
---@param args? yazi.Arguments
function M.yazi(config, input_path, args)
  local utils = require("yazi.utils")
  local YaziProcess = require("yazi.process.yazi_process")
  local yazi_event_handling = require("yazi.event_handling.yazi_event_handling")

  if utils.is_yazi_available() ~= true then
    print(
      "Please install yazi and make sure it is on your `vim.env.PATH`. Check the documentation for more information"
    )
    return
  end

  config =
    vim.tbl_deep_extend("force", configModule.default(), M.config, config or {})

  local Log = require("yazi.log")
  Log.level = config.log_level

  if utils.is_ya_available() ~= true then
    print(
      "Please install ya (the yazi command line utility) and make sure it is on your `vim.env.PATH`. Check the documentation for more information"
    )
    return
  end

  local paths = utils.selected_file_paths(input_path)
  local path = paths[1]

  local prev_win = vim.api.nvim_get_current_win()

  config.chosen_file_path = config.chosen_file_path or vim.fn.tempname()

  local win = require("yazi.window").YaziFloatingWindow.new(config)
  win:open_and_display()
  local yazi_buffer = win.content_buffer

  local yazi_process, yazi_context = YaziProcess:start(config, paths, {
    on_ya_first_event = function(api)
      config.hooks.on_yazi_ready(yazi_buffer, config, api)
      do
        if not (args and args.reveal_path) then
          Log:debug("No reveal_path provided, skipping initial reveal")
          return
        end

        local retries = 15
        require("yazi.process.retry").retry({
          delay = 50,
          retries = retries,
          action = function(retries_remaining)
            local reveal_job = api:reveal(args.reveal_path)
            local completed = reveal_job:wait(500)
            assert(
              completed.code == 0,
              string.format(
                "Failed to reveal path '%s' with exit code: %s, details: %s",
                args.reveal_path,
                completed.code,
                vim.inspect({
                  stdout = completed.stdout,
                  stderr = completed.stderr,
                })
              )
            )
            Log:debug(
              string.format(
                "Revealed path '%s' successfully after retries_remaining: %s",
                args.reveal_path,
                retries_remaining
              )
            )
            return nil
          end,
          on_failure = function(_, retries_remaining)
            Log:debug(
              string.format(
                "Failed to reveal path '%s', retrying after 50ms. retries_remaining: %s",
                args.reveal_path,
                retries_remaining
              )
            )
          end,
          on_final_failure = function(result)
            Log:debug(
              string.format(
                "Failed to reveal path '%s' after %s retries. Details: %s",
                args.reveal_path,
                retries,
                vim.inspect(result)
              )
            )
          end,
        })
      end
    end,
    on_exit = function(
      exit_code,
      selected_files,
      events,
      hovered_url,
      last_directory,
      context
    )
      if exit_code ~= 0 then
        print(
          "yazi.nvim: had trouble opening yazi. Run ':checkhealth yazi' for more information."
        )
        Log:debug(
          string.format("yazi.nvim: had trouble opening yazi: %s", exit_code)
        )
        return
      end

      Log:debug(
        string.format(
          "yazi process exited successfully with code: %s, selected_files %s, and events %s",
          exit_code,
          vim.inspect(selected_files),
          vim.inspect(events)
        )
      )

      -- this is the legacy implementation used when
      -- `future_features.process_events_live = false`. When that is used,
      -- events should be processed in ya_process.lua and should not be
      -- processed a second time here.
      assert(#events == 0 or not config.future_features.process_events_live)

      yazi_event_handling.process_events_emitted_from_yazi(
        events,
        config,
        context
      )

      if last_directory == nil then
        if path:is_file() then
          last_directory = path:parent()
        else
          last_directory = path
        end
        Log:debug(
          string.format(
            "No last_directory provided, presuming the last directory is %s based on the path %s",
            last_directory,
            path.filename
          )
        )
      end

      Log:debug(
        string.format("Resolved the last_directory to %s", last_directory)
      )

      utils.on_yazi_exited(prev_win, win, config, selected_files, {
        last_directory = last_directory,
      })

      if hovered_url then
        -- currently we can't reliably get the hovered_url from ya due to
        -- https://github.com/sxyazi/yazi/issues/1314 so let's try to at least
        -- not corrupt the last working hovered state
        M.previous_state.last_hovered = hovered_url
        Log:debug(
          string.format(
            "Setting the last hovered state to %s",
            vim.inspect(M.previous_state.last_hovered)
          )
        )
      else
        Log:debug(
          "No hovered_url provided, presuming the last hovered file is the initial file"
        )
        M.previous_state.last_hovered = path.filename
      end
    end,
  })

  M.active_contexts:push(yazi_context)

  config.hooks.yazi_opened(path.filename, win.content_buffer, config)

  if config.set_keymappings_function ~= nil then
    config.set_keymappings_function(yazi_buffer, config, yazi_context)
  end

  if config.keymaps ~= false then
    require("yazi.config").set_keymappings(yazi_buffer, config, yazi_context)
  end

  win.on_resized = function(event)
    vim.fn.jobresize(
      yazi_process.yazi_job_id,
      event.win_width,
      event.win_height
    )
  end

  vim.schedule(function()
    vim.cmd("startinsert")
  end)
end

-- Open yazi, continuing from the previously hovered file. If no previous file
-- was hovered, open yazi with the default path.
---@param config? YaziConfig | {}
function M.toggle(config)
  local path = M.previous_state and M.previous_state.last_hovered or nil

  local Log = require("yazi.log")
  if path == nil then
    Log:debug("No previous file hovered, opening yazi with default path")
  else
    Log:debug(
      string.format("Opening yazi with previous file hovered: %s", path)
    )
  end
  if path then
    M.yazi(config, path, { reveal_path = path })
  else
    M.yazi(config, path)
  end
end

M.config = configModule.default()

---@param opts YaziConfig | {}
function M.setup(opts)
  M.config =
    vim.tbl_deep_extend("force", configModule.default(), M.config, opts or {})

  local Log = require("yazi.log")
  Log.level = M.config.log_level

  pcall(function()
    require("yazi.lsp.embedded-lsp-file-operations.lsp-file-operations").setup()
  end)

  local yazi_augroup = vim.api.nvim_create_augroup("yazi", { clear = true })

  if M.config.open_for_directories == true then
    Log:debug("Hijacking netrw to open yazi for directories")
    require("yazi.hijack_netrw").hijack_netrw(yazi_augroup)
  end

  if
    M.config.integrations.picker_add_copy_relative_path_action
    == "snacks.picker"
  then
    require("yazi.integrations.snacks_relative_path").setup_copy_relative_path_picker_action()
  end
end

return M
