vim.pack.add({
    { src = "https://github.com/ellisonleao/gruvbox.nvim" },
    { src = "https://github.com/stevearc/oil.nvim" },
    { src = "https://github.com/echasnovski/mini.pick" },
    { src = "https://github.com/echasnovski/mini.extra" },
    { src = "https://github.com/neovim/nvim-lspconfig" },
    { src = "https://github.com/nvim-treesitter/nvim-treesitter",             version = "main" },
    { src = "https://github.com/nvim-treesitter/nvim-treesitter-textobjects", version = "main" },
    { src = "https://github.com/Saghen/blink.cmp",                            version = "v1.7.0" },
    { src = "https://github.com/mason-org/mason.nvim" },
    { src = "https://github.com/nvim-lualine/lualine.nvim.git" },
    { src = "https://github.com/chomosuke/typst-preview.nvim" },
    { src = "https://codeberg.org/mfussenegger/nvim-jdtls.git" },
    { src = "https://github.com/windwp/nvim-autopairs" },
    { src = "https://codeberg.org/mfussenegger/nvim-dap.git" },
    { src = "https://github.com/akinsho/bufferline.nvim" },
    { src = "https://github.com/nvim-tree/nvim-web-devicons" },
    { src = "https://github.com/echasnovski/mini.ai" },
    { src = "https://github.com/windwp/nvim-ts-autotag" },
    { src = "https://github.com/folke/todo-comments.nvim" },
    { src = "https://github.com/stevearc/conform.nvim" },
    { src = "https://github.com/lewis6991/gitsigns.nvim" },
    { src = "https://github.com/MeanderingProgrammer/render-markdown.nvim" },
    { src = "https://github.com/folke/trouble.nvim" },
    { src = "https://github.com/nvim-neotest/nvim-nio" },
    { src = "https://github.com/rcarriga/nvim-dap-ui" },
    { src = "https://github.com/michaelrommel/nvim-silicon" },
    { src = "https://github.com/hat0uma/csvview.nvim.git" },
    { src = "https://github.com/Thiago4532/mdmath.nvim" },
    { src = "https://github.com/folke/snacks.nvim" },
})

pcall(vim.cmd.colorscheme, "gruvbox")
vim.api.nvim_set_hl(0, "FlashLabel", { fg = "#1d2021", bg = "#fe8019", bold = true })

-- Simple setup({}) plugins
for _, name in ipairs({
    "oil", "mini.pick", "mini.extra", "mason", "typst-preview", "nvim-autopairs",
    "trouble", "gitsigns", "nvim-web-devicons",
    "mini.ai", "nvim-ts-autotag", "todo-comments", "cssview",
}) do
    pcall(function() require(name).setup() end)
end

local prettier = { "prettierd", "prettier", stop_after_first = true }
require("conform").setup({
    formatters_by_ft = {
        python     = { "black" },
        c          = { "clang-format" },
        cpp        = { "clang-format" },
        java       = { "clang-format" },
        javascript = prettier,
        typescript = prettier,
        css        = prettier,
        html       = prettier,
        json       = prettier,
        markdown   = prettier,
        yaml       = prettier,
        haskell    = { "fourmolu" },
    },
    formatters = {
        prettier  = { prepend_args = { "--tab-width", "4", "--use-tabs", "false" } },
        prettierd = { env = { PRETTIERD_DEFAULT_CONFIG = vim.fn.expand("~/.config/nvim/.prettierrc.json") } },
    },
    format_on_save = { timeout_ms = 2000, lsp_format = "fallback" },
})

require("render-markdown").setup({
    latex = { enabled = false }, -- mdmath.nvim renders math as images
    code = { inline_pad = 0, highlight_inline = "RenderMarkdownCode" },
})

require("mdmath").setup({
    dynamic_scale = 0.5,
})

require("snacks").setup({
    image = {
        enabled = true,
        doc = { inline = false },
    },
})

-- Rebuild mdmath JS deps on plugin update
vim.api.nvim_create_autocmd("PackChanged", {
    callback = function(ev)
        if ev.data.spec.name == "mdmath.nvim" and ev.data.kind == "update" then
            vim.system({ "npm", "install" }, { cwd = ev.data.path .. "/mdmath-js" })
        end
    end,
})

vim.api.nvim_create_autocmd("FileType", {
    pattern = "markdown",
    callback = function(ev)
        local win = vim.api.nvim_get_current_win()
        if vim.api.nvim_win_get_config(win).relative == "" then return end
        local buf = ev.buf
        local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
        local changed = false
        for i, line in ipairs(lines) do
            local new = line:gsub("`(\\[^`]-)`", "$%1$")
            if new ~= line then
                lines[i] = new
                changed = true
            end
        end
        if changed then
            vim.bo[buf].modifiable = true
            vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
            vim.bo[buf].modifiable = false
        end
    end,
})

local silicon_bg = {
    typescript = "#1e3a5f",
    javascript = "#5c4a1a",
    java       = "#5c2a1a",
    svelte     = "#5c1f0a",
    css        = "#1f3a5c",
    python     = "#1a3556",
    haskell    = "#3d1f5c",
    c          = "#2a3a4d",
    cpp        = "#2a4d3d",
    swift      = "#5c3a1a",
    lua        = "#1f1f5c",
    markdown   = "#3a2e1f",
    tex        = "#3a2e1f",
    typst      = "#3a2e1f",
    toml       = "#2e2e2e",
    yaml       = "#2e2e2e",
    conf       = "#2e2e2e",
    ini        = "#2e2e2e",
    json       = "#2e2e2e",
}

require("nvim-silicon").setup({
    font = "JetBrainsMono Nerd Font=16",
    theme = "gruvbox-dark",
    pad_horiz = 60,
    pad_vert = 50,
    shadow_color = "#0a0a0a",
    shadow_blur_radius = 10,
    no_round_corner = true,
    output = function()
        return vim.fn.expand("~/Desktop/silicon_")
            .. os.date("!%Y%m%dT%H%M%SZ") .. ".png"
    end,
    window_title = function()
        return vim.fn.fnamemodify(vim.api.nvim_buf_get_name(0), ":t")
    end,
})
-- silicon's --tab-width replaces each tab with a fixed number of spaces
-- instead of advancing to the next tab stop, so tab-indented files (e.g.
-- assembly) come out misaligned. Expand tabs ourselves before shooting.
local s = require("nvim-silicon")
local function expand_tabs(line, ts)
    local out, col = {}, 0
    for i = 1, #line do
        local ch = line:sub(i, i)
        if ch == "\t" then
            local n = ts - (col % ts)
            out[#out + 1] = string.rep(" ", n)
            col = col + n
        else
            out[#out + 1] = ch
            col = col + 1
        end
    end
    return table.concat(out)
end
local orig_format_lines = s.format_lines
s.format_lines = function(cmdline, args, options)
    local lines, cl = orig_format_lines(cmdline, args, options)
    local ts = vim.bo.tabstop
    for i, line in ipairs(lines) do
        lines[i] = expand_tabs(line, ts)
    end
    return lines, cl
end

local function silicon_shot(to_clipboard)
    s.options.background = silicon_bg[vim.bo.filetype] or "#1d2021"
    if to_clipboard then s.clip() else s.file() end
end
vim.keymap.set("x", "<leader>cc", function() silicon_shot(true) end,
    { desc = "Silicon copy" })
vim.keymap.set("x", "<leader>cs", function() silicon_shot(false) end,
    { desc = "Silicon save" })

require("lualine").setup({ options = { theme = "gruvbox_dark" } })

local bl_bg     = "#3c3836" -- lualine statusline bg
local bl_sel_bg = "#504945" -- lualine section_b bg (git branch)
local bl_fg     = "#a89984"
local bl_sel_fg = "#ebdbb2"
require("bufferline").setup({
    highlights = {
        fill                  = { bg = bl_bg },
        background            = { bg = bl_bg, fg = bl_fg },
        buffer_visible        = { bg = bl_bg, fg = bl_fg },
        buffer_selected       = { bg = bl_sel_bg, fg = bl_sel_fg, bold = true, italic = false },
        separator             = { bg = bl_bg, fg = bl_bg },
        separator_visible     = { bg = bl_bg, fg = bl_bg },
        separator_selected    = { bg = bl_sel_bg, fg = bl_bg },
        indicator_selected    = { bg = bl_sel_bg, fg = bl_sel_bg },
        modified              = { bg = bl_bg },
        modified_visible      = { bg = bl_bg },
        modified_selected     = { bg = bl_sel_bg },
        close_button          = { bg = bl_bg, fg = bl_fg },
        close_button_visible  = { bg = bl_bg, fg = bl_fg },
        close_button_selected = { bg = bl_sel_bg, fg = bl_sel_fg },
    },
})
require("blink.cmp").setup({ keymap = { preset = "super-tab" } })

-- Treesitter (main branch: no configs.setup; install parsers manually)
require("nvim-treesitter").install({
    "lua", "vim", "vimdoc", "bash", "c", "cpp", "rust", "python",
    "javascript", "typescript", "tsx", "svelte", "css", "html",
    "json", "toml", "yaml", "markdown", "markdown_inline",
    "java", "typst", "vala",
})

vim.api.nvim_create_autocmd("FileType", {
    callback = function()
        local lang = vim.treesitter.language.get_lang(vim.bo.filetype)
        if lang and not pcall(vim.treesitter.language.inspect, lang) then
            local ok, list = pcall(require("nvim-treesitter").language_list)
            if ok and vim.list_contains(list, lang) then
                require("nvim-treesitter").install(lang)
            end
        end
        pcall(vim.treesitter.start)
    end,
})

-- TS textobjects
local tso = require("nvim-treesitter-textobjects.select")
local textobj = {
    af = "@function.outer",
    ["if"] = "@function.inner",
    ac = "@class.outer",
    ic = "@class.inner",
    al = "@loop.outer",
    il = "@loop.inner"
}
for lhs, query in pairs(textobj) do
    vim.keymap.set({ "x", "o" }, lhs,
        function() tso.select_textobject(query, "textobjects") end)
end

-- Mason: ensure tools
local registry = require("mason-registry")
local ensure = {
    "bash-language-server", "clang-format", "clangd", "java-debug-adapter",
    "jdtls", "json-lsp", "lua-language-server", "rust-analyzer",
    "svelte-language-server", "tailwindcss-language-server", "taplo",
    "typescript-language-server", "pylsp", "black", "vala",
    "prettierd",
}
registry.refresh(function()
    for _, tool in ipairs(ensure) do
        local ok, pkg = pcall(registry.get_package, tool)
        if ok and not pkg:is_installed() then pkg:install() end
    end
end)

-- DAP UI wiring
local dap, dapui = require("dap"), require("dapui")
dapui.setup()
dap.listeners.before.attach.dapui_config = function() dapui.open() end
dap.listeners.before.launch.dapui_config = function() dapui.open() end
