local cmd = vim.api.nvim_command
local M = {}

local c = require('user.themes.nord.colors')
local hi = require('user.util').highlight

-- Set terminal colors
function M.set_vim_termcolors()
    local termcolors = {
        c.grey1,
        c.red,
        c.green,
        c.yellow,
        c.blue,
        c.purple,
        c.cyan,
        c.white1,
        c.grey_bright,
        c.red,
        c.green,
        c.yellow,
        c.blue,
        c.purple,
        c.teal,
        c.white2,
    }

    for index, val in ipairs(termcolors) do
        local key = 'terminal_color_' .. (index - 1)
        vim.g[key] = val
    end
end

-- Editor related groups
function M.highlight_editor()
    -- Editor
    hi('NormalFloat', c.fg, '', '', '')
    hi('FloatBorder', c.fg, '', '', '')
    hi('ColorColumn', '', c.grey1, '', '')
    hi('Cursor', c.black, c.fg, '', '')
    hi('CursorIM', c.black, c.white1, '', '')
    hi('CursorLine', '', c.grey1, '', '')
    hi('TermCursorNC', '', c.grey1, '', '')
    hi('Underlined', c.green, '', 'underline', '')
    hi('Ignore', c.grey1, '', '', '')
    hi('Error', c.fg, c.red, '', '')
    hi('LineNr', c.grey3, '', '', '')
    hi('MatchParen', c.cyan, c.grey3, '', '')
    hi('NonText', c.highlight, '', '', '')
    hi('EndOfBuffer', c.black, '', '', '') -- hide filler line ~ completely
    hi('Normal', c.fg, '', '', '')
    hi('Pmenu', c.fg, c.grey2, '', '')
    hi('PmenuSbar', c.fg, c.grey2, '', '')
    hi('PmenuSel', c.cyan, c.grey3, '', '')
    hi('PmenuThumb', c.cyan, c.grey3, '', '')
    hi('SpecialKey', c.grey3, '', '', '')
    hi('SpellBad', c.red, '', 'undercurl', c.red)
    hi('SpellCap', c.yellow, '', 'undercurl', c.yellow)
    hi('SpellLocal', c.white1, '', 'undercurl', c.white1)
    hi('SpellRare', c.white2, '', 'undercurl', c.white2)
    hi('Visual', '', c.grey2, '', '')
    hi('VisualNOS', '', c.grey2, '', '')

    -- quickfix
    hi('QuickFixLine', '', c.blue, '', '')
    hi('qfLineNr', c.yellow, '', '', '')

    -- :checkhealth
    hi('healthError', c.red, c.grey1, '', '')
    hi('healthSuccess', c.green, c.grey1, '', '')
    hi('healthWarning', c.yellow, c.grey1, '', '')

    -- Gutter
    hi('CursorColumn', '', c.grey1, '', '')
    hi('CursorLineNr', c.fg, '', '', '')
    hi('Folded', c.highlight, c.grey1, '', '')
    hi('FoldColumn', c.grey3, '', '', '')
    hi('SignColumn', c.grey1, '', '', '')

    -- Navigation
    hi('Directory', c.cyan, '', '', '')

    -- Prompt
    cmd('hi! link MsgArea Normal')
    hi('ErrorMsg', c.fg, c.red, '', '')
    hi('ModeMsg', c.fg, '', '', '')
    hi('MoreMsg', c.cyan, '', '', '')
    hi('Question', c.fg, '', '', '')
    hi('WarningMsg', c.black, c.yellow, '', '')
    hi('WildMenu', c.cyan, c.grey1, '', '')

    -- Statusline
    hi('StatusLine', c.cyan, c.grey3, '', '')
    hi('StatusLineNC', c.fg, c.grey3, '', '')
    hi('StatusLineTerm', c.cyan, c.grey3, '', '')
    hi('StatusLineTermNC', c.fg, c.grey3, '', '')

    -- Search
    hi('IncSearch', c.white2, c.dark_blue, 'underline', '')
    hi('Search', c.grey1, c.cyan, '', '')

    -- Tabline
    hi('TabLine', c.fg, c.grey1, '', '')
    hi('TabLineFill', c.fg, c.grey1, '', '')
    hi('TabLineSel', c.cyan, c.grey3, '', '')

    -- Window
    hi('Title', c.fg, '', '', '')
    hi('VertSplit', c.grey_bright, '', '', '')
end

-- Syntax groups
function M.highlight_syntax()
    -- Base syntax
    hi('Boolean', c.blue, '', '', '')
    hi('Character', c.fg, '', '', '')
    hi('Comment', c.grey_bright, '', 'italic', '')
    hi('Conceal', '', '', '', '')
    hi('Conditional', c.blue, '', '', '')
    hi('Constant', c.fg, '', '', '')
    hi('Define', c.blue, '', '', '')
    hi('Delimiter', c.white2, '', '', '')
    hi('Exception', c.blue, '', '', '')
    hi('Float', c.purple, '', '', '')
    hi('Function', c.cyan, '', '', '')
    hi('Identifier', c.fg, '', '', '')
    hi('Include', c.blue, '', '', '')
    hi('Keyword', c.blue, '', 'bold', '')
    hi('Label', c.blue, '', '', '')
    hi('Number', c.purple, '', '', '')
    hi('Operator', c.blue, '', '', '')
    hi('PreProc', c.blue, '', '', '')
    hi('Repeat', c.blue, '', '', '')
    hi('Special', c.fg, '', '', '')
    hi('SpecialChar', c.yellow, '', '', '')
    hi('SpecialComment', c.cyan, '', 'italic', '')
    hi('Statement', c.blue, '', '', '')
    hi('StorageClass', c.blue, '', '', '')
    hi('String', c.green, '', '', '')
    hi('Structure', c.blue, '', '', '')
    hi('Tag', c.fg, '', '', '')
    hi('Todo', c.yellow, '', '', '')
    hi('Type', c.dark_blue, '', 'bold', '')
    hi('Typedef', c.blue, '', '', '')
    cmd('hi! link Macro Define')
    cmd('hi! link PreCondit PreProc')
    cmd('hi! link Variable Identifier')

    -- Diff
    hi('DiffAdd', c.green, c.grey1, '', '')
    hi('DiffChange', c.yellow, c.grey1, '', '')
    hi('DiffDelete', c.red, c.grey1, '', '')
    hi('DiffText', c.blue, c.grey1, '', '')
    -- Legacy diff groups for some plugins
    hi('diffOldFile', c.dark_blue, c.grey1, '', '')
    hi('diffNewFile', c.blue, c.grey1, '', '')
    hi('diffFile', c.cyan, c.grey1, '', '')
    hi('diffLine', c.purple, c.grey1, '', '')
    hi('diffIndexLine', c.fg, c.grey1, '', '')
    cmd('hi! link diffAdded DiffAdd')
    cmd('hi! link diffRemoved DiffDelete')
    cmd('hi! link diffChanged DiffChange')
end

-- No treesitter support yet
function M.highlight_languages()
    -- sql
    cmd('hi! link sqlKeyword Keyword')
    cmd('hi! link sqlSpecial Keyword')

    -- AsciiDoc
    hi('asciidocAttributeEntry', c.dark_blue, '', '', '')
    hi('asciidocAttributeList', c.dark_blue, '', '', '')
    hi('asciidocAttributeRef', c.dark_blue, '', '', '')
    hi('asciidocHLabel', c.blue, '', '', '')
    hi('asciidocListingBlock', c.teal, '', '', '')
    hi('asciidocMacroAttributes', c.purple, '', '', '')
    hi('asciidocOneLineTitle', c.cyan, '', '', '')
    hi('asciidocPassthroughBlock', c.blue, '', '', '')
    hi('asciidocTriplePlusPassthrough', c.teal, '', '', '')
    hi('asciidocAttributeRef', c.purple, '', 'bold', '')
    cmd('hi! link asciidocAdmonition Keyword')
    cmd('hi! link asciidocBackslash Keywork')
    cmd('hi! link asciidocMacro Keyword')
    hi('asciidocQuotedBold', '', '', 'bold', '')
    hi('asciidocQuotedEmphasized', '', '', 'italic', '')
    hi('asciidocQuotedMonospaced', c.teal, '', '', '')
    cmd('hi! link asciidocQuotedMonospaced2 asciidocQuotedMonospaced')
    cmd('hi! link asciidocQuotedUnconstrainedBold asciidocQuotedBold')
    cmd('hi! link asciidocQuotedUnconstrainedEmphasized asciidocQuotedEmphasized')
    cmd('hi! link asciidocURL asciidocMacroAttributes')

    -- jinja (Vim-Jinja2-Syntax)
    hi('jinjaStatement', c.purple, '', 'bold,italic', '')
    hi('jinjaOperator', c.blue, '', '', '')
    hi('jinjaString', c.green, '', '', '')
    hi('jinjaNumber', c.cyan, '', '', '')
    hi('jinjaVariable', c.yellow, '', '', '')

    -- mermaid (mermaid.vim)
    hi('mermaidDiagramType', c.purple, '', 'bold', '')
end

-- Treesitter (:h nvim-treesitter-highlights)
function M.highlight_treesitter()
    hi('TSAnnotation', c.dark_blue, '', 'italic', '')
    hi('TSCharacter', c.green, '', '', '')
    hi('TSConstructor', c.blue, '', '', '')
    hi('TSConstant', c.yellow, '', '', '')
    hi('TSFloat', c.purple, '', '', '')
    hi('TSNumber', c.purple, '', '', '')
    hi('TSString', c.green, '', '', '')

    hi('TSAttribute', c.purple, '', '', '')
    cmd('hi! link TSBoolean Boolean')
    hi('TSConstBuiltin', c.teal, '', '', '')
    hi('TSConstMacro', c.teal, '', '', '')
    hi('TSError', c.red, '', '', '')
    hi('TSException', c.purple, '', '', '')
    hi('TSField', c.teal, '', '', '')
    hi('TSFuncMacro', c.teal, '', '', '')
    hi('TSInclude', c.blue, '', '', '')
    hi('TSLabel', c.purple, '', '', '')
    hi('TSNamespace', c.fg, '', '', '')
    hi('TSOperator', c.blue, '', '', '')
    hi('TSParameter', c.purple, '', 'italic', '')
    hi('TSParameterReference', c.purple, '', 'italic', '')
    hi('TSProperty', c.teal, '', '', '')
    hi('TSPunctDelimiter', c.fg, '', '', '')
    hi('TSPunctBracket', c.cyan, '', '', '')
    hi('TSPunctSpecial', c.cyan, '', '', '')
    hi('TSStringRegex', c.teal, '', '', '')
    hi('TSStringEscape', c.purple, '', '', '')
    hi('TSSymbol', c.purple, '', '', '')
    hi('TSType', c.dark_blue, '', 'bold', '')
    hi('TSTypeBuiltin', c.dark_blue, '', 'bold', '')
    hi('TSTag', c.fg, '', '', '')
    hi('TSTagDelimiter', c.purple, '', '', '')
    hi('TSText', c.fg, '', '', '')
    hi('TSTextReference', c.purple, '', '', '')
    hi('TSStrong', c.fg, '', 'bold', '')
    hi('TSEmphasis', c.fg, '', 'bold,italic', '')
    hi('TSUnderline', '', '', 'underline', '')
    hi('TSStrike', c.orange, '', 'italic', '')
    hi('TSTitle', c.dark_blue, '', 'bold', '')
    hi('TSLiteral', c.green, '', 'italic', '')
    hi('TSURI', c.green, '', '', '')

    cmd('hi! link TSComment Comment')
    hi('TSConditional', c.blue, '', 'bold', '')
    hi('TSKeyword', c.blue, '', 'bold', '')
    hi('TSRepeat', c.blue, '', 'bold', '')
    hi('TSKeywordFunction', c.blue, '', 'bold', '')
    hi('TSKeywordOperator', c.blue, '', 'bold', '')
    cmd('hi! link TSFunction Function')
    hi('TSMethod', c.teal, '', '', '')
    cmd('hi! link TSFuncBuiltin Function')
    cmd('hi! link TSVariable Variable')
    cmd('hi! link TSVariableBuiltin Variable')
    cmd('hi! link TSStructure Structure')

    hi('TSNote', c.blue, '', 'bold', '')
    hi('TSWarning', c.yellow, '', 'bold', '')
    hi('TSDanger', c.red, '', 'bold', '')
end

-- LSP groups
function M.highlight_lsp()
    hi('DiagnosticError', c.red, '', '', '')
    hi('DiagnosticWarn', c.yellow, '', '', '')
    hi('DiagnosticInfo', c.blue, '', '', '')
    hi('DiagnosticHint', c.cyan, '', '', '')

    hi('DiagnisticUnderlineError', '', '', 'underline', c.red)
    hi('DiagnosticUnderlineWarn', '', '', 'underline', c.yellow)
    hi('DiagnosticUnderlineInfo', '', '', 'underline', c.blue)
    hi('DiagnosticUnderlineHint', '', '', 'underline', c.cyan)

    hi('DiagnosticVirtualTextError', c.red, '', 'italic', '')
    hi('DiagnosticVirtualTextWarn', c.yellow, '', 'italic', '')
    hi('DiagnosticVirtualTextInfo', c.blue, '', 'italic', '')
    hi('DiagnosticVirtualTextHint', c.cyan, '', 'italic', '')

    cmd('hi! link DiagnosticFloatingError DiagnosticError')
    cmd('hi! link DiagnosticFloatingWarn DiagnosticWarn')
    cmd('hi! link DiagnosticFloatingInfo DiagnosticInfo')
    cmd('hi! link DiagnosticFloatingHint DiagnosticHint')

    cmd('hi! link DiagnosticSignError DiagnosticError')
    cmd('hi! link DiagnosticSignWarn DiagnosticWarn')
    cmd('hi! link DiagnosticSignInfo DiagnosticInfo')
    cmd('hi! link DiagnosticSignHint DiagnosticHint')

    hi('LspReferenceText', c.fg, c.grey_bright, '', '')
    hi('LspReferenceRead', c.fg, c.grey_bright, '', '')
    hi('LspReferenceWrite', c.fg, c.grey_bright, '', '')
    cmd('hi! link LspCodeLens Comment')
end

-- Specify groups for plugins
function M.highlight_plugins()
    -- nvim-cmp
    hi('CmpItemAbbr', c.fg, '', '', '')
    hi('CmpItemAbbrMatch', c.yellow, '', 'bold', '')
    hi('CmpItemAbbrMatchFuzzy', c.yellow, '', 'bold', '')
    hi('CmpItemAbbrDeprecated', c.highlight, '', 'strikethrough', '')
    hi('CmpItemKind', c.green, '', 'bold', '')
    hi('CmpItemMenu', c.blue, '', 'bold', '')

    -- LuaSnip
    hi('LuaSnipChoice', c.orange, '', '', '')
    hi('LuaSnipInsert', c.blue, '', '', '')

    -- Gitsigns
    hi('GitSignsAdd', c.green, '', 'bold', '')
    hi('GitSignsAddNr', c.green, '', '', '')
    hi('GitSignsChange', c.yellow, '', 'bold', '')
    hi('GitSignsChangeNr', c.yellow, '', '', '')
    hi('GitSignsDelete', c.red, '', 'bold', '')
    hi('GitSignsDeleteNr', c.red, '', '', '')
    hi('GitSignsCurrentLineBlame', c.grey_bright, '', 'italic,bold', '')

    -- dap.nvim
    hi('DapSignDefault', c.orange, '', '', '')
    hi('DapSignRejected', c.red, '', '', '')

    -- ts-rainbow
    hi('rainbowcol1', c.red, '', 'bold', '')
    hi('rainbowcol2', c.orange, '', 'bold', '')
    hi('rainbowcol3', c.yellow, '', 'bold', '')
    hi('rainbowcol4', c.green, '', 'bold', '')
    hi('rainbowcol5', c.cyan, '', 'bold', '')
    hi('rainbowcol6', c.blue, '', 'bold', '')
    hi('rainbowcol7', c.purple, '', 'bold', '')

    -- hop.nvim
    hi('HopNextKey', c.red, '', 'bold', '')
    hi('HopNextKey1', c.cyan, '', 'bold', '')
    hi('HopNextKey2', c.dark_blue, '', '', '')
    cmd('hi! link HopUnmatched LineNr')

    -- dashboard-nvim / alpha-nvim
    hi('DashboardHeader', c.blue, '', 'bold', '')
    hi('DashboardCenter', c.green, '', 'bold', '')
    hi('DashboardShortcut', c.purple, '', 'bold,italic', '')
    hi('DashboardFooter', c.yellow, '', 'bold', '')

    -- symbols-outline.nvim
    hi('FocusedSymbol', c.yellow, '', 'bold', '')
    hi('SymbolsOutlineConnector', c.blue, '', '', '')

    -- NvimTree
    hi('NvimTreeNormal', c.fg, '', '', '')
    hi('NvimTreeIndentMarker', c.grey3, '', '', '')
    hi('NvimTreeFolderIcon', c.fg, '', '', '')
    hi('NvimTreeRootFolder', c.teal, '', 'bold', '')
    hi('NvimTreeFolderName', c.blue, '', '', '')
    hi('NvimTreeEmptyFolderName', c.grey_bright, '', '', '')
    hi('NvimTreeImageFile', c.yellow, '', '', '')
    hi('NvimTreeExecFile', c.green, '', '', '')
    hi('NvimTreeSpecialFile', c.dark_blue, '', 'underline', '')
    hi('NvimTreeGitDirty', c.yellow, '', '', '')
    hi('NvimTreeGitNew', c.green, '', '', '')
    hi('NvimTreeGitDeleted', c.red, '', '', '')
    cmd('hi! link NvimTreeWindowPicker WindowPicker')

    -- WhichKey
    hi('WhichKey', c.green, '', 'bold', '')
    hi('WhichKeyGroup', c.cyan, '', '', '')
    hi('WhichKeyDesc', c.purple, '', '', '')
    hi('WhichKeySeperator', c.grey_bright, '', '', '')
    cmd('hi! link WhichKeyFloat NormalFloat')
    cmd('hi! link WhichKeyValue Comment')

    -- nvim-notify
    hi('NotifyERRORBorder', c.red, '', '', '')
    hi('NotifyWARNBorder', c.yellow, '', '', '')
    hi('NotifyINFOBorder', c.blue, '', '', '')
    hi('NotifyDEBUGBorder', c.green, '', '', '')
    hi('NotifyTRACEBorder', c.purple, '', '', '')
    hi('NotifyERRORIcon', c.red, '', '', '')
    hi('NotifyWARNIcon', c.yellow, '', '', '')
    hi('NotifyINFOIcon', c.blue, '', '', '')
    hi('NotifyDEBUGIcon', c.green, '', '', '')
    hi('NotifyTRACEIcon', c.purple, '', '', '')
    hi('NotifyERRORTitle', c.red, '', '', '')
    hi('NotifyWARNTitle', c.yellow, '', '', '')
    hi('NotifyINFOTitle', c.blue, '', '', '')
    hi('NotifyDEBUGTitle', c.green, '', '', '')
    hi('NotifyTRACETitle', c.purple, '', '', '')

    -- Indent Blankline
    hi('IndentBlanklineChar', c.grey1, '', '', '')
    hi('IndentBlanklineContextChar', c.grey_bright, '', '', '')

    -- nvim-treesitter-context
    cmd('hi! link TreesitterContext Pmenu')

    -- orgmode.nvim
    hi('OrgHeadlineLevel1', c.purple, '', 'bold', '')
    hi('OrgHeadlineLevel2', c.dark_blue, '', 'bold', '')
    hi('OrgHeadlineLevel3', c.blue, '', 'bold', '')
    hi('OrgHeadlineLevel4', c.cyan, '', 'bold', '')
    hi('OrgHeadlineLevel5', c.teal, '', 'bold', '')
    hi('OrgHeadlineLevel6', c.green, '', 'bold', '')
    hi('OrgTSCheckboxChecked', c.grey3, '', 'bold', '')
    hi('OrgTSCheckboxUnchecked', c.green, '', 'bold', '')
    hi('OrgTSCheckboxHalfChecked', c.blue, '', 'bold', '')
    hi('OrgAgendaDealine', c.red, '', 'bold', '')
    hi('OrgAgendaScheduled', c.green, '', 'bold', '')
    hi('OrgAgendaScheduledPast', c.blue, '', 'bold', '')

    -- window-picker.nvim
    hi('WindowPicker', c.white2, c.blue, 'bold', '')
    hi('WindowPickerSwap', c.white2, c.orange, 'bold', '')

    -- trouble.nvim
    hi('LspTroubleText', c.blue, '', 'bold', '')

    -- Telescope
    hi('TelescopePromptBorder', c.cyan, '', 'bold', '')
    hi('TelescopeResultsBorder', c.blue, '', 'bold', '')
    hi('TelescopePreviewBorder', c.green, '', 'bold', '')
    hi('TelescopeSelection', c.fg, c.grey2, '', '')
    hi('TelescopeMultiSelection', c.fg, c.grey2, 'bold', '')
    hi('TelescopeSelectionCaret', c.red, c.grey2, 'bold', '')
    hi('TelescopeMatching', c.yellow, '', 'bold', '')
    hi('TelescopePromptTitle', c.black, c.cyan, 'bold', '')
    hi('TelescopePreviewTitle', c.black, c.green, 'bold', '')
    hi('TelescopeResultsTitle', c.black, c.blue, 'bold', '')

    -- Neogit
    hi('NeogitBranch', c.purple, '', '', '')
    hi('NeogitRemote', c.blue, '', '', '')
    hi('NeogitHunkHeader', c.cyan, c.grey2, 'bold', '')
    hi('NeogitHunkHeaderHighlight', c.yellow, c.grey2, 'bold', '')
    hi('NeogitDiffContextHighlight', c.fg, c.grey2, '', '')
    hi('NeogitDiffDeleteHighlight', c.red, c.grey2, '', '')
    hi('NeogitDiffAddHighlight', c.green, c.grey2, '', '')
    hi('NeogitNotificationInfo', c.green, '', '', '')
    hi('NeogitNotificationWarning', c.yellow, '', '', '')
    hi('NeogitNotificationError', c.red, '', '', '')

    -- fidget.nvim
    hi('FidgetTitle', c.green, '', 'bold', '')
    hi('FidgetTask', c.blue, '', 'italic', '')
end

return M
