-- Mappings.
-- See `:help vim.diagnostic.*` for documentation on any of the below functions
local opts = { noremap=true, silent=true }

-- vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float, opts)
-- vim.keymap.set('n', '<leader>h', vim.diagnostic.hide, opts)
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts)
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, opts)

-- Use an on_attach function to only map the following keys
-- after the language server attaches to the current buffer
vim.api.nvim_create_autocmd("LspAttach", {
   callback = function(args)

      local client = vim.lsp.get_client_by_id(args.data.client_id)
      local bufopts = { noremap=true, silent=true, buffer=args.buf }

      -- KEY MAP

      vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts)
      vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts)
      vim.keymap.set('n', 'K', function() vim.lsp.buf.hover { border = { "", "" ,"", " ", "", "", "", " " } } end, bufopts)
      vim.keymap.set('n', 'gI', vim.lsp.buf.implementation, bufopts)
      vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, bufopts)
      vim.keymap.set('n', '<leader>wa', vim.lsp.buf.add_workspace_folder, bufopts)
      vim.keymap.set('n', '<leader>wr', vim.lsp.buf.remove_workspace_folder, bufopts)
      vim.keymap.set('n', '<leader>wl', function()
       print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
      end, bufopts)
      vim.keymap.set('n', '<leader>y', vim.lsp.buf.type_definition, bufopts)
      vim.keymap.set('n', '<leader>V', vim.lsp.buf.rename, bufopts)
      vim.keymap.set({'n','v'}, '<leader>ca', vim.lsp.buf.code_action, bufopts)
      vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts)
      vim.keymap.set('n', '<leader>=', function() vim.lsp.buf.format { async = true } end, bufopts)

      -- DIAGNOSTICS

      vim.api.nvim_create_autocmd("CursorMoved", {
        callback = function()
           vim.diagnostic.open_float(nil, {
              focusable = false,
              close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" },
              source = false,
              prefix = ' ',
              scope = 'cursor',
           })
        end
      })

   -- -- PATCH: override all diagnostic highlights to be severity based
   -- -- to mitigate severity being ignored in the special cases of DiagnosticDeprecated and DiagnosticUnnecessary
   -- --
   -- -- foollow relevant issues:
   -- -- #26796 (nvim) https://github.com/neovim/neovim/issues/26796#issuecomment-3236801970
   -- -- #1677 (kickstart.nvim)
   -- -- #1550 (kickstart.nvim)
   -- --
      -- Create namespace for our custom highlights
      local ns_id = vim.api.nvim_create_namespace('diagnostic_text_highlight')
      -- Function to apply highlights to diagnostic ranges
      local function highlight_diagnostic_text()
        -- Clear previous highlights
        vim.api.nvim_buf_clear_namespace(0, ns_id, 0, -1)
        -- Get diagnostics for current buffer
        local diagnostics = vim.diagnostic.get(0)
        for _, diagnostic in ipairs(diagnostics) do
          local severity = diagnostic.severity
          local start_line = diagnostic.lnum
          local start_col = diagnostic.col
          local end_line = diagnostic.end_lnum or start_line
          local end_col = diagnostic.end_col or (start_col + 1)
          -- Choose highlight group based on severity
          local hl_group
          if severity == vim.diagnostic.severity.ERROR then
            hl_group = 'DiagnosticError'
          elseif severity == vim.diagnostic.severity.WARN then
            hl_group = 'DiagnosticWarn'
          elseif severity == vim.diagnostic.severity.INFO then
            hl_group = 'DiagnosticInfo'
          elseif severity == vim.diagnostic.severity.HINT then
            hl_group = 'DiagnosticHint'
          end
          -- Apply highlight to the specific range
          if hl_group then
            vim.highlight.range(
              0,                    -- buffer (0 = current)
              ns_id,               -- namespace
              hl_group,            -- highlight group
              { start_line, start_col }, -- start position
              { end_line, end_col }      -- end position
            )
          end
        end
      end
      -- Create autocmd for DiagnosticChanged event
      vim.api.nvim_create_autocmd('DiagnosticChanged', {
        callback = highlight_diagnostic_text,
        desc = 'Highlight diagnostic text with custom colors'
      })
      -- Also apply highlights when entering a buffer (for existing diagnostics)
      vim.api.nvim_create_autocmd('BufEnter', {
        callback = highlight_diagnostic_text,
        desc = 'Apply diagnostic text highlights on buffer enter'
      })
   -- --

--    -- COMPLETION ( disabled while still immature, using nvim-blink for now )

--    -- Enable auto-completion. Note: Use CTRL-Y to select an item. |complete_CTRL-Y|
--    if client:supports_method('textDocument/completion') then
--      -- Optional: trigger autocompletion on EVERY keypress. May be slow!
--      local chars = {}; for i = 32, 126 do table.insert(chars, string.char(i)) end

--      client.server_capabilities.completionProvider.triggerCharacters = chars

--      vim.lsp.completion.enable(true, client.id, args.buf, {
--         autotrigger = true
--      })

--    end

--    -- FORMATTING

--    -- Auto-format ("lint") on save.
--    -- Usually not needed if server supports "textDocument/willSaveWaitUntil".
--    if not client:supports_method('textDocument/willSaveWaitUntil')
--        and client:supports_method('textDocument/formatting') then
--      vim.api.nvim_create_autocmd('BufWritePre', {
--        group = vim.api.nvim_create_augroup('my.lsp', {clear=false}),
--        buffer = args.buf,
--        callback = function()
--          vim.lsp.buf.format({ bufnr = args.buf, id = client.id, timeout_ms = 1000 })
--        end,
--      })
--    end

   end,
})


-- CONFIGS

vim.diagnostic.config({
   virtual_text = false,
-- signs = false,
   signs = {
      text = {
      -- [vim.diagnostic.severity.ERROR] = "• ",
      -- [vim.diagnostic.severity.WARN]  = "• ",
      -- [vim.diagnostic.severity.INFO]  = "• ",
      -- [vim.diagnostic.severity.HINT]  = "• ",
         [vim.diagnostic.severity.ERROR] = "",
         [vim.diagnostic.severity.WARN]  = "",
         [vim.diagnostic.severity.INFO]  = "",
         [vim.diagnostic.severity.HINT]  = "",
      },
      numhl = {
         [vim.diagnostic.severity.ERROR] = "DiagnosticError",
         [vim.diagnostic.severity.WARN]  = "DiagnosticWarn",
         [vim.diagnostic.severity.INFO]  = "DiagnosticInfo",
         [vim.diagnostic.severity.HINT]  = "DiagnosticHint",
      },
   -- linehl = {
   --    [vim.diagnostic.severity.ERROR] = "DiagnosticError",
   --    [vim.diagnostic.severity.WARN]  = "DiagnosticWarn",
   --    [vim.diagnostic.severity.INFO]  = "DiagnosticInfo",
   --    [vim.diagnostic.severity.HINT]  = "DiagnosticHint",
   -- },
   },
   update_in_insert = false,
   severity_sort = true,
   float = {
      border = { "", "" ,"", " ", "", "", "", " " },
   },
})

--

vim.lsp.config('*', {
   flags = {
      debounce_text_changes = 150,
   },
})

vim.lsp.config('hls', {
   filetypes = { 'haskell', 'lhaskell', 'cabal' },
})

vim.lsp.config('lua_ls', {
   root_markers = {},
   settings = {
      Lua = {
         telemetry = {
            enable = false,
         },
         runtime = { version = 'Lua 5.1' },
         diagnostics = {
            globals = { 'bit', 'vim', 'it', 'describe', 'before_each', 'after_each' },
         },
      },
   },
   on_init = function(client)
      local nvim_settings = {
         runtime = {
            -- Tell the language server which version of Lua you're using
            version = 'LuaJIT',
         },
         diagnostics = {
            -- Get the language server to recognize the `vim` global
            globals = {'vim'}
         },
         workspace = {
            checkThirdParty = false,
            library = {
               -- Make the server aware of Neovim runtime files
               vim.env.VIMRUNTIME,
               vim.fn.stdpath('config'),
            },
         },
      }
      client.config.settings.Lua = vim.tbl_deep_extend(
         'force',
         client.config.settings.Lua,
         nvim_settings
      )
   end,
})

vim.lsp.enable({
   'lua_ls',
   'rust_analyzer',
   'hls',
   'ts_ls'
})